zoukankan      html  css  js  c++  java
  • Fiolki

    时间限制: 3 Sec  内存限制: 128 MB

    题目描述

    化学家吉丽想要配置一种神奇的药水来拯救世界。

    吉丽有n种不同的液体物质,和n个药瓶(均从1到n编号)。初始时,第i个瓶内装着g[i]克的第i种物质。吉丽需要执行一定的步骤来配置药水,第i个步骤是将第a[i]个瓶子内的所有液体倒入第b[i]个瓶子,此后第a[i]个瓶子不会再被用到。瓶子的容量可以视作是无限的。

    吉丽知道某几对液体物质在一起时会发生反应产生沉淀,具体反应是1克c[i]物质和1克d[i]物质生成2克沉淀,一直进行直到某一反应物耗尽。生成的沉淀不会和任何物质反应。当有多于一对可以发生反应的物质在一起时,吉丽知道它们的反应顺序。每次倾倒完后,吉丽会等到反应结束后再执行下一步骤。

    吉丽想知道配置过程中总共产生多少沉淀。

    输入

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

    输出

    配置过程中总共产生多少沉淀。

    样例输入

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

    样例输出

    6


    题解
            题目并不复杂,而且有很多可以利用的性质,比如说每个反应只会进行一次,所有物质在遇到反应物之前并没有什么用之类的,但是还是只想到了n^2的并查集+链表做法,水了30。通过这道题学会了一种很神奇的东西叫重构树,即每倾倒一次就新建一个节点作为这两个节点的父亲,然后以此类推,可以想见每一个反应一定是在LCA上发生的,然后我们就可以欢快地按优先级处理每个点发生的反应,只要倒着加边反应就会按优先级从大到小进行。重构树作为一种新思路让这道题一下子简明了起来,不过我实现得有点繁冗,因为用的是离线LCA,再加上把每个反应倒序加到LCA上一共用了三个邻接表两个并查集。

     

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int sj1=200005;
    const int sj2=500005;
    const int sj3=sj1+sj2;
    int n,m,k,f[sj3],g[sj1],yz[sj2],yy[sj2],h[sj1],zx[sj3];
    int tp,d[sj3],e1,e2,lca[sj2],fa[sj2],size,w[sj3];
    long long ans;
    bool r[sj3];
    int read()
    {
        int jg=0,jk=getchar()-'0';
        if(jk<=9&&jk>0) jg=jk;
        jk=getchar()-'0';
        while(jk<=9&&jk>=0)
           jg=jg*10+jk,jk=getchar()-'0';
        return jg;
    }
    int find(int x)
    {
        if(f[x]==-1) return x;
        f[x]=find(f[x]);
        return f[x];
    }
    void hb(int x,int y)
    {
        x=find(x),y=find(y);
        if(x!=y) f[x]=y;
    }
    int fi(int x)
    {
        if(w[x]==-1) return x;
        w[x]=fi(w[x]);
        return w[x];
    }
    void hbb(int x,int y)
    {
         x=fi(x),y=fi(y);
         if(x!=y) w[x]=y;
    }
    struct tree
    {
        int v,ne,num;     
    }t[sj2<<1];
    struct B
    {
        int v,ne;
    }b[sj2<<2];
    void ad1(int x,int y,int z)
    {
         t[e1].v=y,t[e1].ne=h[x];
         t[e1].num=z,h[x]=e1++;
    }
    void ad2(int x,int y)
    {
         b[e2].v=y,b[e2].ne=d[x];
         d[x]=e2++;
    }
    void init()
    {
         memset(d,-1,sizeof(d));
         memset(h,-1,sizeof(h));
         memset(f,-1,sizeof(f));
         memset(w,-1,sizeof(w));
         n=read(),m=read(),k=read();
         size=n;
         for(int i=1;i<=n;i++)  g[i]=read();
         for(int i=1;i<=m;i++) 
         {
           tp=read(),e1=read();
           size++;
           ad2(find(tp),size),ad2(find(e1),size);
           ad2(size,find(tp)),ad2(size,find(e1));
           hb(tp,size),hb(e1,size);
         }
         for(int i=1;i<=k;i++)  yz[i]=read(),yy[i]=read();
         e1=0;
         for(int i=k;i>=1;i--)
           ad1(yz[i],yy[i],i),ad1(yy[i],yz[i],i);
    }
    void tarjan(int x)
    {
         r[x]=1,zx[x]=x;
         for(int i=d[x];i!=-1;i=b[i].ne)
         {
           if(!r[b[i].v])
           {
             tarjan(b[i].v);
             hb(x,b[i].v);
             zx[find(b[i].v)]=x;
           }
           hbb(x,b[i].v);
         }
         if(x<=n)
           for(int i=h[x];i!=-1;i=t[i].ne)
             if(r[t[i].v]&&fi(x)==fi(t[i].v))
               fa[t[i].num]=zx[find(t[i].v)];
    }
    int main()
    {
        init();
        memset(f,-1,sizeof(f));
        for(int i=n+m;i>=1;i--)
          if(!r[i])  tarjan(i);
        memset(b,0,sizeof(b));
        memset(d,-1,sizeof(d));
        for(int i=k;i>=1;i--)
          if(fa[i])
            ad2(fa[i],i);
        for(int i=n+1;i<=n+m;i++)
          for(int j=d[i];j!=-1;j=b[j].ne)
          {
             tp=b[j].v;
             if(g[yy[tp]]==0||g[yz[tp]]==0) continue;
             if(g[yy[tp]]<=g[yz[tp]])
             {
                ans+=g[yy[tp]];
                g[yz[tp]]-=g[yy[tp]],g[yy[tp]]=0;
             }
             else
             {
                ans+=g[yz[tp]];
                g[yy[tp]]-=g[yz[tp]],g[yz[tp]]=0;
             }
          }
        printf("%lld",ans<<1);
        return 0;
    }
    fio
     
  • 相关阅读:
    Qomolangma实现篇(二):命名空间和别名子系统的实现
    关于Borland's IDE:发生了就发生了吧!
    Qomolangma实现篇(六):Qomo的OOP框架的实现技术
    Qomolangma实现篇(八):Qomo中的AOP框架
    经典的《JavaScript 权威指南》中的“对象”不经典
    Qomo OpenProject beta1 发布!
    弹出当前索引号案例
    tab栏切换效果案例
    [USACO18DEC]Sort It Out P
    [ABC163F]path pass i
  • 原文地址:https://www.cnblogs.com/moyiii-/p/7500219.html
Copyright © 2011-2022 走看看