• 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;
    }
    
    
  • 相关阅读:
    交换机的配置文件和系统映像文件备份与恢复(如果不小心损坏了,可以用这种方法恢复)
    交换机端口安全配置
    路由器密码重置(不是适用于所有有些启动顺序数字不一样)
    交换机的默认网关(跨网段telnet)
    思科交换机的初始配置(使用telnet登录)
    Linux命令集(第一部分共40个)
    Linux6.9安装
    javamail邮件发送报错解决方案
    isEmpty()与equals()、==“”区别
    eclipse svn 修改了类名之后提交
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7572817.html
Copyright © 2020-2023  润新知