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
",ans);
}

int main()
{
	work();
	return 0;
}

原文地址:https://www.cnblogs.com/Yuzao/p/7572817.html