zoukankan      html  css  js  c++  java
  • bzoj 3712: [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

    HINT 

    Source

    鸣谢Jcvb

    jesseliu的讲课题,思路和Kruskal重构树的思想比较像。。。

    因为每个瓶子倒进一个瓶子之后就废了,那么每个瓶子只有唯一的父亲,那么倾倒操作构成了树结构。。。

    然后我们用Peaks类似的方法,把两个瓶子合起来的时候新建一个点表示合并后的瓶子。。。

    这样做的好处就是可以维护好每个瓶子内的化学用品还剩多少,因为合并不影响原来瓶子的信息。。。

    然后两个反应物相遇的时间就是其Lca的深度,反应的优先级就是序号,

    那么我们按照其Lca为第一关键字,反应的优先级为第二关键字排序,然后依次处理反应即可。。。

    // MADE BY QT666
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int N=2000050;
    int fa[N],g[N],dfn[N],n,m,k,tt,tot;
    int head[N],to[N],nxt[N],cnt;
    int size[N],son[N],deep[N],tmp,top[N],father[N];
    void lnk(int x,int y){
      to[++cnt]=y,nxt[cnt]=head[x],head[x]=cnt;
      to[++cnt]=x,nxt[cnt]=head[y],head[y]=cnt;
    }
    void dfs1(int x,int f){
      size[x]=1;deep[x]=deep[f]+1;
      for(int i=head[x];i;i=nxt[i]){
        int y=to[i];if(y==f) continue;
        dfs1(y,x);father[y]=x;size[x]+=size[y];
        if(size[y]>size[son[x]]) son[x]=y;
      }
    }
    void dfs2(int x,int f){
      top[x]=f;dfn[x]=++tmp;
      if(son[x]) dfs2(son[x],f);
      for(int i=head[x];i;i=nxt[i]){
        int y=to[i];
        if(y==father[x]||y==son[x]) continue;
        dfs2(y,y);
      }
    }
    int Lca(int x,int y){
      while(top[x]!=top[y]){
        if(deep[top[x]]<deep[top[y]]) swap(x,y);
        x=father[top[x]];
      }
      if(deep[x]<deep[y]) swap(x,y);
      return y;
    }
    struct data{
      int x,y,Lca,id;
    }q[N];
    bool cmp(const data &a,const data &b){
      if(deep[a.Lca]==deep[b.Lca]) return a.id<b.id;
      return deep[a.Lca]>deep[b.Lca];
    }
    int find(int x){
      if(x!=fa[x]) fa[x]=find(fa[x]);
      return fa[x];
    }
    int main(){
      scanf("%d%d%d",&n,&m,&k);tt=n;
      for(int i=1;i<=n;i++) scanf("%d",&g[i]);
      for(int i=1;i<=n;i++) fa[i]=i;
      for(int i=1;i<=m;i++){
        int x,y;scanf("%d%d",&x,&y);
        tt++;x=find(x),y=find(y);
        lnk(tt,x);lnk(tt,y);fa[x]=fa[y]=tt;fa[tt]=tt;
      }
      for(int i=1;i<=tt;i++) if(find(i)==i) dfs1(i,0),dfs2(i,i);
      for(int i=1;i<=k;i++){
        int x,y;scanf("%d%d",&x,&y);
        if(find(x)==find(y)) q[++tot]=(data){x,y,Lca(x,y),i};
      }
      sort(q+1,q+1+tot,cmp);ll ans=0;
      for(int i=1;i<=tot;i++){
        int res=min(g[q[i].x],g[q[i].y]);
        g[q[i].x]-=res,g[q[i].y]-=res,ans+=1ll*(res<<1);
      }
      printf("%lld
    ",ans);
      return 0;
    }
    

      

  • 相关阅读:
    cpu进程调度---RT Throttling【转】
    Google 开发新的开源系统 Fuchsia
    牛人博客!!!各大招聘网站信息实时查询浏览【转】
    ARM多核处理器启动过程分析【转】
    Linux 下多核CPU知识【转】
    Android的init过程(二):初始化语言(init.rc)解析【转】
    In_interrupt( ) 和In_irq( )【转】
    jiffies溢出与时间先后比较-time_after,time_before【转】
    Linux系统的中断、系统调用和调度概述【转】
    linux中断的上半部和下半部 【转】
  • 原文地址:https://www.cnblogs.com/qt666/p/7470115.html
Copyright © 2011-2022 走看看