码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 3712: [PA2014]Fiolki

时间:2017-01-22 13:50:59      阅读:216      评论:0      收藏:0      [点我收藏+]

标签:top   esc   过程   表示   script   bool   ++   二叉树   content   

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;
}

 

bzoj 3712: [PA2014]Fiolki

标签:top   esc   过程   表示   script   bool   ++   二叉树   content   

原文地址:http://www.cnblogs.com/ccz181078/p/6339922.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!