[BZOJ3712]Fiolki 重构树(并查集)
Posted LadyLex
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ3712]Fiolki 重构树(并查集)相关的知识,希望对你有一定的参考价值。
3712: [PA2014]Fiolki
Time Limit: 30 Sec Memory Limit: 128 MBDescription
化学家吉丽想要配置一种神奇的药水来拯救世界。
吉丽有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
此后第a[i]个瓶子不会再被用到.
对于每一对可以反应的物质,他们可能,也只可能在他们重构树上lca处反应
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <vector> 5 using namespace std; 6 const int N=200010,K=500010; 7 typedef long long LL; 8 LL sum; 9 int n,m,k,w[N],fa[N<<1],bin[25]; 10 int e,adj[N<<1],cnt,f[N<<1][19],deep[N<<1]; 11 int find(int a){return fa[a]==a?a:fa[a]=find(fa[a]);} 12 inline int min(int a,int b){return a<b?a:b;} 13 struct data{int a,b;data(int x=0,int y=0){a=x,b=y;}}step[N]; 14 struct edge{int zhong,next;}s[N<<1]; 15 vector<data>re[N<<1]; 16 inline void add(int qi,int zhong) 17 {s[++e].zhong=zhong;s[e].next=adj[qi];adj[qi]=e;} 18 void dfs(int rt) 19 { 20 deep[rt]=deep[f[rt][0]]+1; 21 for(int i=adj[rt];i;i=s[i].next) 22 dfs(s[i].zhong); 23 } 24 inline void ST() 25 { 26 for(int i=1;i<=18;i++) 27 for(int j=1;j<=cnt;j++) 28 f[j][i]=f[f[j][i-1]][i-1]; 29 } 30 inline int LCA(int a,int b) 31 { 32 if(deep[a]<deep[b])swap(a,b); 33 int cha=deep[a]-deep[b]; 34 for(int j=18;~j;j--) 35 if(cha&bin[j])a=f[a][j]; 36 if(a==b)return a; 37 for(int j=18;~j;j--) 38 if(f[a][j]!=f[b][j])a=f[a][j],b=f[b][j]; 39 return f[a][0]; 40 } 41 int main() 42 { 43 bin[0]=1;for(int i=1;i<=20;i++)bin[i]=bin[i-1]<<1; 44 int a,b,lca;scanf("%d%d%d",&n,&m,&k);cnt=n; 45 for(int i=1;i<=n+m;i++)fa[i]=i; 46 for(int i=1;i<=n;i++)scanf("%d",&w[i]); 47 for(int i=1;i<=m;i++) 48 scanf("%d%d",&step[i].a,&step[i].b), 49 a=find(step[i].a),b=find(step[i].b), 50 fa[a]=fa[b]=f[a][0]=f[b][0]=++cnt, 51 add(cnt,a),add(cnt,b); 52 ST(); 53 for(int i=1;i<=cnt;i++) 54 if(!deep[i])dfs(find(i)); 55 for(int i=1;i<=k;i++) 56 { 57 scanf("%d%d",&a,&b); 58 if(find(a)==find(b)) 59 lca=LCA(a,b),re[lca].push_back(data(a,b)); 60 } 61 for(int i=n+1;i<=cnt;i++) 62 for(int j=0,len=re[i].size();j<len;j++) 63 a=min(w[re[i][j].a],w[re[i][j].b]), 64 w[re[i][j].a]-=a,w[re[i][j].b]-=a,sum+=a; 65 printf("%lld\\n",sum<<1); 66 }
以上是关于[BZOJ3712]Fiolki 重构树(并查集)的主要内容,如果未能解决你的问题,请参考以下文章
[HDU 3712] Fiolki (带边权并查集+启发式合并)