zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    几种滑动验证码处理
    面试题 四 redis线上为什么不能使用 keys *命令
    面试题 六 squid 的理解
    从XP到WIN10,各个系统版本自带 .NET版本整理
    SQL压缩日志
    sql server 使用链接服务器远程查询
    FastReport几个问题
    .Net 三款工作流引擎比较:WWF、netBPM 和 ccflow
    ClientDataSet控件ApplyUpdates的异常触发
    Delphi中关于字符串截取详解
  • 原文地址:https://www.cnblogs.com/wfj2048/p/7511133.html
Copyright © 2011-2022 走看看