Description
化学家吉丽想要配置一种神奇的药水来拯救世界。
吉丽有n种不同的液体物质,和n个药瓶(均从1到n编号)。初始时,第i个瓶内装着g[i]克的第i种物质。吉丽需要执行一定的步骤来配置药水,第i个步骤是将第a[i]个瓶子内的所有液体倒入第b[i]个瓶子,此后第a[i]个瓶子不会再被用到。瓶子的容量可以视作是无限的。
吉丽知道某几对液体物质在一起时会发生反应产生沉淀,具体反应是1克c[i]物质和1克d[i]物质生成2克沉淀,一直进行直到某一反应物耗尽。生成的沉淀不会和任何物质反应。当有多于一对可以发生反应的物质在一起时,吉丽知道它们的反应顺序。每次倾倒完后,吉丽会等到反应结束后再执行下一步骤。
吉丽想知道配置过程中总共产生多少沉淀。
Input
第一行三个整数n,m,k(0<=m<n<=200000,0<=k<=500000),分别表示药瓶的个数(即物质的种数),操作步数,可以发生的反应数量。
第二行有n个整数g[1],g[2],…,g[n](1<=g[i]<=10^9),表示初始时每个瓶内物质的质量。
接下来m行,每行两个整数a[i],b[i](1<=a[i],b[i]<=n,a[i]≠b[i]),表示第i个步骤。保证a[i]在以后的步骤中不再出现。
接下来k行,每行是一对可以发生反应的物质c[i],d[i](1<=c[i],d[i]<=n,c[i]≠d[i]),按照反应的优先顺序给出。同一个反应不会重复出现。
操作的过程可以看做一棵二叉树/森林,叶节点为药瓶,其余节点对应于操作,求lca可以找出一个反应发生的那次操作,然后在树上dfs一次模拟求出答案
#include<cstdio> char buf[16000000],*ptr=buf-1; const int N=200007; int _(){ int x=0,c=*++ptr; while(c<48)c=*++ptr; while(c>47)x=x*10+c-48,c=*++ptr; return x; } int n,m,k,g[N]; int ch[N*2][2],fa[N*2],son[N*2],sz[N*2],dep[N*2],top[N*2],f[N*2],idp,v[500007][2]; int es[500007],enx[500007],e0[500007],ep=2; long long ans=0; bool ed[N*2]; void f1(int w,int pa){ dep[w]=dep[fa[w]=pa]+1; sz[w]=1; if(w>n) for(int i=0;i<2;++i){ int u=ch[w][i]; f1(u,w); sz[w]+=sz[u]; if(sz[u]>sz[son[w]])son[w]=u; } } void f2(int w,int tp){ top[w]=tp; if(son[w])f2(son[w],tp); if(w>n) for(int i=0;i<2;++i){ int u=ch[w][i]; if(u!=son[w])f2(u,u); } } int min(int a,int b){return a<b?a:b;} void dec(int w){ int x=v[w][0],y=v[w][1],z=min(g[x],g[y]); g[x]-=z,g[y]-=z,ans+=z; } void f3(int w){ if(w>n) for(int i=0;i<2;++i)f3(ch[w][i]); for(int i=e0[w];i;i=enx[i])dec(es[i]); } int lca(int x,int y){ int a=top[x],b=top[y]; while(a!=b){ if(dep[a]>dep[b])x=fa[a],a=top[x]; else y=fa[b],b=top[y]; } return dep[x]<dep[y]?x:y; } int get(int x){ int a=x,c; while(x!=f[x])x=f[x]; while(x!=f[a])c=f[a],f[a]=x,a=c; return x; } int main(){ fread(buf,1,sizeof(buf),stdin); idp=n=_();m=_();k=_(); for(int i=1;i<=n;++i)g[i]=_(),f[i]=i; for(int i=1,a,b;i<=m;++i){ a=_(),b=_(); ++idp; a=get(a),b=get(b); ch[idp][0]=a; ch[idp][1]=b; ed[a]=ed[b]=1; f[a]=f[b]=f[idp]=idp; } for(int i=1;i<=idp;++i)if(!ed[i])f1(i,0),f2(i,i); for(int i=1;i<=k;++i)v[i][0]=_(),v[i][1]=_(); for(int i=k;i;--i){ int c=lca(v[i][0],v[i][1]); if(c)es[ep]=i,enx[ep]=e0[c],e0[c]=ep++; } for(int i=1;i<=idp;++i)if(!ed[i])f3(i); printf("%lld\n",ans<<1); return 0; }