化学家吉丽想要配置一种神奇的药水来拯救世界。
吉丽有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]<= 109 ),表示初始时每个瓶内物质的质量。
接下来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]) ,按照反应的优先顺序给出。同一个反应不会重复出现。
总共产生多少沉淀
暴力模拟的话……需要考虑的东西太多了:每个瓶子的药剂的种类、质量,以及何时反应,与什么反应……存都存不下……
先分析一下影响反应发生先后顺序的因素:
1.反应发生的时间
2.反应发生的优先级
其中1优先于2
有没有什么办法只关心反应发生的时间和优先级,又能求出答案?
如果从某种药剂出发,要么是倒入其他瓶中,要么是其他药剂倒入它所在的瓶子中,发生某某反应,是一个线状的过程。因此我们可以想到将每个瓶子抽象成一个点,把瓶子A倒入瓶子B,就由A向B连边。由于A、B混合后的B不同于原来的B,不妨将A和B连向新的点C,表示A、B混合后的B。
这样经过一系列操作后,会得到一颗或多棵树(把它倒过来看,除根以外每个点的入度皆为1)。对于药剂i和j,它们反应的场所就是对应树上的LCA。我们记录下每组会发生反应的药剂的LCA的深度,那么深度越大的就越先发生。
预处理出每组药剂的LCA,将它们的深度为第一关键字,优先度为第二关键字,排序一遍,就解决了反应发生先后顺序的问题,模拟一遍即可。
时间复杂度为O( klogn )。
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN=400010;
const int MAXM=500010;
int n,m,k,g[MAXN],a[MAXN],b[MAXN],c[MAXM],d[MAXM],Fa[MAXN],pn,cnt,tot;
int fa[MAXN][20],dep[MAXN],dfn;
bool vis[MAXN];
ll ans;
int head[MAXN];
struct edge{int to,nxt;}e[MAXM<<1];
struct reaction{
int x,y,d,t;
reaction(){}
reaction(int t1,int t2,int t3,int t4){
x=t1; y=t2; d=t3; t=t4;
}
}rea[MAXM];
bool cmp(reaction t1,reaction t2){
return t1.d>t2.d || t1.d==t2.d && t1.tint getint(){
int v=0; char ch;
while(!isdigit(ch=getchar())); v=ch-48;
while(isdigit(ch=getchar())) v=v*10+ch-48; return v;
}
void insert(int u,int v){
e[++cnt].to=v; e[cnt].nxt=head[u]; head[u]=cnt;
}
int find(int x){
return Fa[x]==x?x:Fa[x]=find(Fa[x]);
}
void dfs(int x){
vis[x]=true;
for(int i=1;(1<1]][i-1];
for(int i=head[x];i;i=e[i].nxt){
dep[e[i].to]=dep[x]+1;
fa[e[i].to][0]=x;
dfs(e[i].to);
}
}
int lca(int x,int y){
if(dep[x]int det=dep[x]-dep[y];
for(int i=0;(1<if((1<if(x==y) return x;
for(int i=18;~i;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int main(){
n=getint(); m=getint(); k=getint(); pn=n;
for(int i=1;i<=n;i++) g[i]=getint(),Fa[i]=i;
for(int i=1;i<=m;i++) a[i]=getint(),b[i]=getint();
for(int i=1;i<=k;i++) c[i]=getint(),d[i]=getint();
for(int i=1;i<=m;i++){
++pn;
int f1=find(a[i]),f2=find(b[i]);
insert(pn,f1);
insert(pn,f2);
Fa[f1]=Fa[f2]=Fa[pn]=pn;
}
for(int i=pn;i;i--)
if(!vis[i]) dfn++,dfs(i);
for(int i=1;i<=k;i++){
if(find(c[i])==find(d[i]))
rea[++tot]=reaction(c[i],d[i],dep[lca(c[i],d[i])],i);
}
sort(rea+1,rea+1+tot,cmp);
for(int i=1;i<=tot;i++){
int x=rea[i].x,y=rea[i].y,det=min(g[x],g[y]);
g[x]-=det; g[y]-=det; ans+=det<<1;
}
printf("%lld\n",ans);
return 0;
}