Fiolki题解

问题 B: 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

 乱搞压正解,暴力出奇迹。
 数据水到一定地步,当时本来期望打50分的暴力A了……
 
  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<queue>
  6 #include<algorithm>
  7 #include<cmath>
  8 #define N 200005
  9 using namespace std;
 10 int n,m,t,zz2;
 11 int g[N],a[N],b[N];
 12 int f[N][2],zz;
 13 struct ro{
 14     int to,l,from;
 15     int next;
 16     bool friend operator > (ro a,ro b)
 17     {
 18         return a.l>b.l;
 19     }
 20 }road[1000005],road2[1000006];
 21 void build(int x,int y,int z){
 22     zz++;
 23     road[zz].to=y;
 24     road[zz].from=x;
 25     road[zz].l=z;
 26     road[zz].next=a[x];
 27     a[x]=zz;
 28 }
 29 void build2(int x,int y){
 30     zz2++;
 31     road2[zz2].from=x;
 32     road2[zz2].to=y;
 33     road2[zz2].next=b[x];
 34     b[x]=zz2;
 35 }
 36 int fa[N];
 37 int find(int x){
 38     if(fa[x]==x)return x;
 39     fa[x]=find(fa[x]);
 40     return fa[x];
 41 }
 42 long long hav[N];
 43 void hb(int a,int b){
 44     int x=find(a);
 45     int y=find(b);
 46     fa[x]=y;
 47     hav[y]+=hav[x];
 48     build2(y,x);
 49 }
 50 bool cle[N],cle2[N];
 51 priority_queue<ro,vector<ro>,greater<ro > > q1;
 52 void dfs(int x,int tt){
 53     //cout<<x<<endl
 54     if(!cle2[x])
 55     {
 56         for(int i=a[x];i>0;i=road[i].next)
 57         {
 58             int y=road[i].to;
 59             if(find(y)==tt)
 60             {
 61                 q1.push(road[i]);
 62             }
 63         }
 64     }
 65     bool yx=1;
 66     for(int i=b[x];i>0;i=road2[i].next)
 67     {
 68         int y=road2[i].to;
 69         if(!cle[y])
 70         {
 71             //yx=0;
 72             dfs(y,tt);
 73         }
 74         if(!cle[y])
 75         {
 76             yx=0;       
 77         }
 78     }
 79     cle[x]=yx&cle2[x];
 80 }
 81 int main(){
 82     scanf("%d%d%d",&n,&m,&t);
 83     for(int i=1;i<=n;i++)
 84         scanf("%d",&g[i]);
 85     for(int i=1;i<=m;i++)
 86         scanf("%d%d",&f[i][0],&f[i][1]);
 87     for(int i=1;i<=t;i++)
 88     {
 89         int x,y;
 90         scanf("%d%d",&x,&y);
 91         build(x,y,i);
 92         build(y,x,i);
 93     }
 94     for(int i=1;i<=n;i++)
 95         fa[i]=i;
 96     for(int i=1;i<=m;i++)
 97     {
 98         int from=f[i][0],to=f[i][1];
 99         dfs(from,to);
100         while(!q1.empty())
101         {
102             ro tt=q1.top();
103             q1.pop();
104             int x=tt.from,y=tt.to;
105             int p=min(g[x],g[y]);
106             g[x]-=p;
107             g[y]-=p;
108             hav[to]+=p*2;
109             if(!g[x]) cle2[x]=1;
110             if(!g[y]) cle2[y]=1;
111         }
112         hb(from,to);
113     }
114     long long sum=0;
115     for(int i=1;i<=n;i++)
116     {
117         if(find(i)==i)
118         {
119             sum+=hav[i];
120         }
121     }
122     printf("%lld
",sum);
123     //while(1);
124     return 0;
125 }
暴力
 下面我来说一下我的正解。 
 貌似他们说正解是一个叫做克鲁斯卡尔重构树的东西,不过我不会,于是乎借鉴了一下思想乱搞出一下时间复杂度不是玄学的东西。
 首先如果我们假设每两个瓶子倒在一起之后都被扔掉,然后我们重新找一个瓶子装一下,那么我们就可以发现整个就是一个完美二叉树树林,能反应的两瓶药品如果反应一定是在他们的LCA上于是我们求一下离线LCA(之所以不用倍增是因为炸内存)。然后利用一个邻接表存一下发生在该节点的反应。然后按照他给的步骤去模拟设定一个now数组表示该药品实际在哪个节点,每合并一次就把合并后的节点的反应放进优先队列里面,处理一下就好了。
 
  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<queue>
  6 #include<algorithm>
  7 #include<cmath>
  8 #include<vector>
  9 #define N 1000005
 10 using namespace std;
 11 int n,m,t,zz;
 12 long long g[N];
 13 struct qu{
 14     int x,y;
 15     int next;
 16     int yxj;
 17     bool friend operator >(qu a,qu b)
 18     {
 19         return a.yxj>b.yxj;
 20     }
 21 }que[1000004];
 22 struct ro{
 23     int to,next,l;
 24 }road[1000005];
 25 int b[N*2],zz3;
 26 void bui(int x,int y){
 27     zz3++;
 28     road[zz3].to=y;
 29     road[zz3].next=b[x];
 30     b[x]=zz3;
 31 }
 32 struct no{
 33     int son[2],bh,fa;
 34     long long hav;
 35 }node[N*2];
 36 int zz2,now[N],a[N],fa[N],f2[N];
 37 void build(int x,int y,int z)
 38 {
 39     zz2++;
 40     que[zz2].x=x,que[zz2].y=y;
 41     que[zz2].yxj=z;
 42     que[zz2].next=a[x];
 43     a[x]=zz2;
 44 }
 45 int find(int x)
 46 {
 47     if(fa[x]==x)return x;
 48     else return fa[x]=find(fa[x]);
 49 }
 50 void hb(int x,int y)
 51 {
 52     int aa=find(x),bb=find(y);
 53     if(aa!=bb)
 54         fa[aa]=bb;
 55 }
 56 bool vis[N];
 57 void work(int x)
 58 {
 59     f2[x]=x;
 60     vis[x]=1;
 61     if(node[x].son[0])
 62     {
 63         work(node[x].son[0]);
 64         hb(x,node[x].son[0]);
 65         f2[find(x)]=x;
 66          
 67         work(node[x].son[1]);
 68         hb(x,node[x].son[1]);
 69         f2[find(x)]=x;
 70     }
 71     for(int i=a[x];i>0;i=que[i].next)
 72     {
 73         int y=que[i].y;
 74         if(vis[y])
 75         {
 76             bui(f2[find(y)],i);
 77         }
 78     }
 79 }
 80 priority_queue<qu,vector<qu>,greater<qu > > q1;
 81 int f[N][2];
 82 int main(){
 83     scanf("%d%d%d",&n,&m,&t);
 84     zz=n;
 85     for(int i=1;i<=n;i++) node[i].bh=i,now[i]=i;
 86     for(int i=1;i<=n;i++)
 87         scanf("%lld",&g[i]);
 88     for(int i=1;i<=m;i++)
 89     {
 90         int x,y;
 91         scanf("%d%d",&x,&y);
 92         zz++;
 93         node[now[x]].fa=node[now[y]].fa=zz;
 94         node[zz].bh=y;
 95         node[zz].son[0]=now[x],node[zz].son[1]=now[y];
 96         now[y]=zz;
 97         f[i][0]=x,f[i][1]=y;
 98     }
 99     for(int i=1;i<=zz;i++)
100         fa[i]=i;
101     for(int i=1;i<=t;i++)
102     {
103         int x,y;
104         scanf("%d%d",&x,&y);
105         build(x,y,i);
106         build(y,x,i);
107     }
108  
109     for(int i=1;i<=zz;i++)
110     {
111         if(!node[i].fa)
112         {
113             memset(vis,0,sizeof(vis));
114             work(i);
115         }
116         if(i<=n)
117             now[i]=i;
118     }
119     long long ans=0;
120     for(int i=1;i<=m;i++)
121     {
122         int from=f[i][0],to=f[i][1];
123         int x=now[from],y=now[to];
124         int ff=node[x].fa;
125         for(int j=b[ff];j>0;j=road[j].next)
126             q1.push(que[road[j].to]);
127         while(!q1.empty())
128         {
129             qu aa=q1.top();
130             int p=min(g[aa.x],g[aa.y]);
131             g[aa.x]-=p;
132             g[aa.y]-=p;
133             node[ff].hav+=2*p;
134             q1.pop();
135         }
136         node[ff].hav+=node[y].hav+node[x].hav;
137         now[to]=ff;
138     }
139      
140     for(int i=1;i<=zz;i++)
141     {
142         if(!node[i].fa)
143         {
144             ans+=node[i].hav;
145         }
146     }
147     printf("%lld
",ans);
148     //while(1);
149     return 0;
150 }
LCA做法
 
原文地址:https://www.cnblogs.com/liutianrui/p/7470086.html