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],bi,表示第i个步骤。保证a[i]在以后的步骤中不再出现。
接下来k行,每行是一对可以发生反应的物质c[i],di,按照反应的优先顺序给出。同一个反应不会重复出现。
Output
Sample Input
3 2 1
2 3 4
1 2
3 2
2 3
Sample Output
6
解题报告:
很容易想到:如果按操作建图,最后反应的顺序就是lca的深度,所以我们按照操作建好图,然后求出所有lca的深度,最后排个序就可以做了
那么问题来了:
如果先将3倒入1,再将2倒入1,1.2.3之间都可以反应,那么就不清楚反应顺序了,所以跟操作顺序也有很大关系,所以建图不能简单的直接从x连到y,需要新建一个节点,保证先输入的深度更大,那么就没有问题了.
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N=800005,M=500005;
int head[N],num=0,to[N<<1],nxt[N<<1],n,a[N],m,Q,dep[N],fa[N],top[N];
int son[N],sz[N],ids=0,col[N];
void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
void dfs1(int x,int co){
int u;sz[x]=1;col[x]=co;
for(int i=head[x];i;i=nxt[i]){
u=to[i];if(dep[u])continue;
dep[u]=dep[x]+1;fa[u]=x;
dfs1(u,co);sz[x]+=sz[u];
if(sz[u]>sz[son[x]])son[x]=u;
}
}
void dfs2(int x,int tp){
top[x]=tp;
if(son[x])dfs2(son[x],tp);
for(int i=head[x];i;i=nxt[i])
if(to[i]!=fa[x] && to[i]!=son[x])
dfs2(to[i],to[i]);
}
struct node{
int x,y,id,lca;
bool operator <(const node &pr)const{
if(dep[lca]!=dep[pr.lca])return dep[lca]>dep[pr.lca];
return id<pr.id;
}
}e[M];
int lca(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
return x;
}
int Fa[N],du[N];
void work()
{
int x,y;
scanf("%d%d%d",&n,&m,&Q);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),Fa[i]=i;
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
link(i+n,Fa[x]);link(Fa[y],i+n);
link(Fa[x],i+n);link(i+n,Fa[y]);
Fa[y]=i+n;
}
for(int i=n+m;i>=1;i--)
if(!dep[i])dep[i]=1,dfs1(i,++ids),dfs2(i,i);
for(int i=1;i<=Q;i++){
scanf("%d%d",&e[i].x,&e[i].y);
if(col[e[i].x]!=col[e[i].y])continue;
e[i].lca=lca(e[i].x,e[i].y);
e[i].id=i;
}
sort(e+1,e+Q+1);long long ans=0,res;
for(int i=1;i<=Q;i++){
x=e[i].x;y=e[i].y;
if(col[x]!=col[y])continue;
res=Min(a[x],a[y]);ans+=res<<1;
a[x]-=res;a[y]-=res;
}
printf("%lld\n",ans);
}
int main()
{
work();
return 0;
}