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

3 2 1
2 3 4
1 2
3 2
2 3

Sample Output

6

正解:构树+倍增。

类似于$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
",ans); return 0;
78 }
原文地址:https://www.cnblogs.com/wfj2048/p/7511133.html