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]),按照反应的优先顺序给出。同一个反应不会重复出现。

Sample Input

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

Sample Output

6
不是很会做,想了很多数据结构都不是很资瓷
看了一发路牌:LCA考虑LCA做法
对于合并两个瓶子,就看做一个新节点连向这两个节点,最终会构成一棵树
然后对于每对关系,发生的一定是两个节点在同一颗树里,先后顺序按照LCA的深度判定
建图时跑了个并查集维护
代码如下:
//MT_LI
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
int n,m,T;
struct node{
    int x,y,next;
}a[410000];int len,last[410000];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}
int f[410000][21],dep[410000];
int g[210000];int bin[21];
int fa[410000];
int v[410000];
void dfs(int x,int fa)
{
    v[x]=1;
    dep[x]=dep[fa]+1;f[x][0]=fa;
    for(int i=1;bin[i]<=dep[x];i++)f[x][i]=f[f[x][i-1]][i-1];
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fa)dfs(y,x);
    }
}
int findfa(int x)
{
    if(fa[x]!=x)fa[x]=findfa(fa[x]);
    return fa[x];
}
int LCA(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);
    for(int i=19;i>=0;i--)
        if(dep[x]-bin[i]>=dep[y])
            x=f[x][i];
    if(x==y)return x;
    for(int i=19;i>=0;i--)
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}
struct Q{
    int x,y,dep,id;
}q[510000];
typedef long long ll;
bool cmp(Q a,Q b){return a.dep!=b.dep?a.dep>b.dep:a.id<b.id;}
int main()
{
    bin[0]=1;
    for(int i=1;i<=19;i++)bin[i]=bin[i-1]<<1;
    len=0;memset(last,0,sizeof(last));
    scanf("%d%d%d",&n,&m,&T);
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=n;i++)scanf("%d",&g[i]);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        int fx=findfa(x),fy=findfa(y);
        n++;ins(n,fx);ins(n,fy);fa[n]=n;
        fa[fx]=n,fa[fy]=n;
    }    
    memset(v,0,sizeof(v));
    for(int i=1;i<=n;i++)
        if(!v[i])
        {
            int root=findfa(i);
            dep[root]=0;dfs(root,0);
        }
    for(int i=1;i<=T;i++)
    {
        scanf("%d%d",&q[i].x,&q[i].y);
        if(findfa(q[i].x)!=findfa(q[i].y)){q[i].dep=-1<<30;continue;}
        q[i].dep=dep[LCA(q[i].x,q[i].y)];q[i].id=i;
    }
    sort(q+1,q+1+T,cmp);
    ll ans=0ll;
    for(int i=1;q[i].dep!=-1<<30&&i<=T;i++)
    {
        int tt;
        ans+=2*(tt=min(g[q[i].x],g[q[i].y]));
        g[q[i].x]-=tt,g[q[i].y]-=tt;
    }
    printf("%lld\n",ans);
    return 0;    
}

 

posted @ 2018-11-01 21:58  MT_LI  阅读(182)  评论(0编辑  收藏  举报