[bzoj3712][PA2014]Fiolki_倍增LCA

Fiolki bzoj-3712 PA-2014

题目大意题目链接

注释:略。


想法

神题!

我们建树:对于一次倾倒操作,我们弄一个新的大瓶子作为两个合并瓶子的父亲节点,与两个瓶子相连。

对于一个给定的化学反应,显然他们在这棵又操作构成的森林中他们的LCA处实现。

所以我们对于所有的操作直接建树。

我们枚举所有的反应,每个反应对应两个物质的LCA。我们将反应按照对应LCA的深度为第一关键字,反应的优先级为第二关键字排序。

紧接着我们顺次枚举所有的反应,统计答案并将相应物质剩余量相减即可。

最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 200010 
#define K 500010 
using namespace std;
int to[N<<2],nxt[N<<2],head[N<<1],tot;
int F[N<<1],f[21][N<<1],dep[N<<1];
int a[N],cnt;
inline char nc() {static char *p1,*p2,buf[100000]; return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}
int rd() {int x=0; char c=nc(); while(!isdigit(c)) c=nc(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=nc(); return x;}
inline void add(int x,int y) {to[++tot]=y; nxt[tot]=head[x]; head[x]=tot;}
int find(int x) {return F[x]==x?x:F[x]=find(F[x]);}
struct Node {int x,y,fr,dp;}opr[K];
inline bool cmp(const Node &a,const Node &b) {return a.dp==b.dp?a.fr<b.fr:a.dp>b.dp;}
void dfs(int pos,int fa)
{
	dep[pos]=dep[fa]+1;
	f[0][pos]=fa; for(int i=1;i<=20;i++) f[i][pos]=f[i-1][f[i-1][pos]];
	for(int i=head[pos];i;i=nxt[i]) if(to[i]!=fa) dfs(to[i],pos);
}
int lca(int x,int y)
{
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=20;~i;i--) if(dep[f[i][x]]>=dep[y]) x=f[i][x];
	if(x==y) return x;
	for(int i=20;~i;i--) if(f[i][x]!=f[i][y]) x=f[i][x],y=f[i][y];
	return f[0][x];
}
int main()
{
    // freopen("3712.in","r",stdin);
    // freopen("3712.out","w",stdout);
	int n=rd(),m=rd(),k=rd(); for(int i=1;i<=n;i++) a[i]=rd(),F[i]=i;
    for(int i=1;i<=n*2;i++) F[i]=i;
	cnt=n;
	for(int i=1;i<=m;i++)
	{
		int x=find(rd()),y=find(rd());
		cnt++;
		add(cnt,x);
		add(cnt,y);
		F[x]=F[y]=cnt;
	}
	dfs(cnt,cnt);
	for(int i=1;i<=k;i++) opr[i].x=rd(),opr[i].y=rd(),opr[i].fr=i,opr[i].dp=dep[lca(opr[i].x,opr[i].y)];
	sort(opr+1,opr+k+1,cmp);
	int ans=0;
	for(int i=1;i<=k;i++)
	{
		int now=min(a[opr[i].x],a[opr[i].y]);
		ans+=now;
		a[opr[i].x]-=now; a[opr[i].y]-=now;
	}
	printf("%lld
",(long long)ans*2);
    // fclose(stdin); fclose(stdout);
	return 0;
}

小结:好题啊,关键是发现其中树形结构并想到LCA处发生反应。

原文地址:https://www.cnblogs.com/ShuraK/p/9891301.html