bzoj3712 [PA2014]Fiolki
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]),按照反应的优先顺序给出。同一个反应不会重复出现。
Output
Sample Input
2 3 4
1 2
3 2
2 3
Sample Output
正解:构树+倍增。
类似于$kruskal$重构树的方法,我们可以把反应关系搞成一棵树的关系,也就是每次把两个药瓶所在的根都连在一个新建点上,所有药瓶都是叶子结点。
构树以后,我们就能很好地处理反应顺序了。如果两个瓶子不在一棵树上,那么直接忽略这个反应,否则两个瓶子在$lca$处会碰到一起,药瓶里的药水会发生反应。那么很显然,$lca$深的肯定会先反应,如果深度相同,那么按照优先级先后反应。
排出反应顺序以后,我们就可以直接模拟得出答案了。
1 #include <bits/stdc++.h> 2 #define il inline 3 #define RG register 4 #define ll long long 5 #define N (500010) 6 7 using namespace std; 8 9 struct edge{ int nt,to; }g[N]; 10 struct data{ int x,y,u,i; }q[N]; 11 12 int f[21][N],fa[N],dep[N],head[N],vi[N],a[N],n,m,k,fg,num,cnt,tot; 13 ll ans; 14 15 il int gi(){ 16 RG int x=0,q=1; RG char ch=getchar(); 17 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 18 if (ch=='-') q=-1,ch=getchar(); 19 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 20 return q*x; 21 } 22 23 il int cmp(const data &a,const data &b){ 24 if (dep[a.u]==dep[b.u]) return a.i<b.i; 25 return dep[a.u]>dep[b.u]; 26 } 27 28 il void insert(RG int from,RG int to){ 29 g[++num]=(edge){head[from],to},head[from]=num; return; 30 } 31 32 il int find(RG int x){ 33 return fa[x]==x ? x : fa[x]=find(fa[x]); 34 } 35 36 il void dfs(RG int x,RG int p){ 37 f[0][x]=p,dep[x]=dep[p]+1,vi[x]=fg; 38 for (RG int i=head[x];i;i=g[i].nt) dfs(g[i].to,x); 39 return; 40 } 41 42 il int lca(RG int u,RG int v){ 43 if (u==v) return u; 44 if (dep[u]<dep[v]) swap(u,v); 45 for (RG int i=19;i>=0;--i) 46 if (dep[f[i][u]]>=dep[v]) u=f[i][u]; 47 if (u==v) return u; 48 for (RG int i=19;i>=0;--i) 49 if (f[i][u]!=f[i][v]) u=f[i][u],v=f[i][v]; 50 return f[0][u]; 51 } 52 53 int main(){ 54 #ifndef ONLINE_JUDGE 55 freopen("fiolki.in","r",stdin); 56 freopen("fiolki.out","w",stdout); 57 #endif 58 n=gi(),m=gi(),k=gi(),cnt=n; 59 for (RG int i=1;i<=n;++i) a[i]=gi(); 60 for (RG int i=1;i<=n+m;++i) fa[i]=i; 61 for (RG int i=1,u,v,x,y;i<=m;++i){ 62 u=gi(),v=gi(),x=find(u),y=find(v); 63 fa[x]=fa[y]=++cnt,insert(cnt,x),insert(cnt,y); 64 } 65 for (RG int i=1;i<=n+m;++i) if (find(i)==i) ++fg,dfs(i,0); 66 for (RG int j=1;j<=19;++j) 67 for (RG int i=1;i<=n+m;++i) f[j][i]=f[j-1][f[j-1][i]]; 68 for (RG int i=1,x,y;i<=k;++i){ 69 x=gi(),y=gi(); if (vi[x]!=vi[y]) continue; 70 q[++tot]=(data){x,y,lca(x,y),i}; 71 } 72 sort(q+1,q+tot+1,cmp); 73 for (RG int i=1,res;i<=tot;++i){ 74 res=min(a[q[i].x],a[q[i].y]),ans+=res<<1; 75 a[q[i].x]-=res,a[q[i].y]-=res; 76 } 77 printf("%lld\n",ans); return 0; 78 }