zoukankan      html  css  js  c++  java
  • BZOJ3712: [PA2014]Fiolki

    BZOJ3712: [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],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]),按照反应的优先顺序给出。同一个反应不会重复出现。

    Output

    Sample Input

    3 2 1
    2 3 4
    1 2
    3 2
    2 3

    Sample Output

    6

    题解Here!
    有思维难度的图论题。
    先说一种错误的做法:

    直接把反应的步骤连边,遇到可以反应的物质就判断这两种物质在不在一张图里。

    这当然是极其标准的错误解法,因为这样完全没有考虑反应在时间上的先后顺序。

    我当时就是这么想的,然后被我自己给$Hack$了$emmm......$

    正解是这样的:

    如果两个反应发生,要考虑两点:

    1. 反应发生的时间。
    2. 反应的优先程度。

    并且要先考虑$1$,再考虑$2$。

    反应时间可以通过$LCA$解决:

    每两个反应连在一个新的点上,这个点就代表了这两种物质,两种物质的$LCA$的深度就是它们反应时间的先后顺序。

    煮个栗子:

    比如共有$3$个瓶子,$2$个反应。

    $1$和$2$先混合,那么就把$1,2$挂在$4$号节点的儿子上。

    如果$3$再和$2$混合,那么就把$3$和$4$挂在$5$号节点的儿子上。

    $1$与$3$的$LCA$是$5$,深度为$1$,相当于它们最后混合在一起。

    最后$sort$一下,然后直接模拟反应过程即可。

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #define MAXN 400010
    #define MAXM 500010
    using namespace std;
    int n,m,k,c=1,d=0,root;
    int val[MAXN],pos[MAXN];
    int head[MAXN],deep[MAXN],son[MAXN],size[MAXN],fa[MAXN],id[MAXN],top[MAXN];
    struct Tree{
    	int next,to;
    }a[MAXN<<1];
    struct Question{
    	int x,y,deep,id;
    }que[MAXM];
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    inline bool cmp(const Question &p,const Question &q){
    	if(p.deep==q.deep)return p.id<q.id;
    	return p.deep>q.deep;
    }
    inline void add(int x,int y){
    	a[c].to=y;a[c].next=head[x];head[x]=c++;
    	a[c].to=x;a[c].next=head[y];head[y]=c++;
    }
    inline void add_que(int x,int y,int lca,int id){
    	d++;
    	que[d].x=x;que[d].y=y;que[d].deep=deep[lca];
    	que[d].id=id;
    }
    void dfs1(int rt){
    	son[rt]=0;size[rt]=1;
    	for(int i=head[rt];i;i=a[i].next){
    		int will=a[i].to;
    		if(!deep[will]&&will!=fa[rt]){
    			deep[will]=deep[rt]+1;
    			fa[will]=rt;
    			id[will]=id[rt];
    			dfs1(will);
    			size[rt]+=size[will];
    			if(size[son[rt]]<size[will])son[rt]=will;
    		}
    	}
    }
    void dfs2(int rt,int f){
    	top[rt]=f;
    	if(son[rt])dfs2(son[rt],f);
    	for(int i=head[rt];i;i=a[i].next){
    		int will=a[i].to;
    		if(will!=fa[rt]&&will!=son[rt])dfs2(will,will);
    	}
    }
    int LCA(int x,int y){
    	while(top[x]!=top[y]){
    		if(deep[top[x]]<deep[top[y]])swap(x,y);
    		x=fa[top[x]];
    	}
    	if(deep[x]>deep[y])swap(x,y);
    	return x;
    }
    void work(){
    	int x,y;
    	long long ans=0;
    	sort(que+1,que+d+1,cmp);
    	for(int i=1;i<=d;i++){
    		x=que[i].x;y=que[i].y;
    		int w=min(val[x],val[y]);
    		val[x]-=w;val[y]-=w;
    		ans+=w;
    	}
    	printf("%lld
    ",(ans<<1));
    }
    void init(){
    	int x,y;
    	n=read();m=read();k=read();
    	root=n;
    	for(int i=1;i<=n;i++){
    		val[i]=read();
    		pos[i]=i;
    	}
    	for(int i=1;i<=m;i++){
    		x=read();y=read();
    		root++;
    		add(root,pos[x]);add(root,pos[y]);
    		pos[y]=root;
    	}
    	for(int i=root;i>=1;i--)
    	if(!deep[i]){
    		deep[i]=1;id[i]=i;
    		dfs1(i);
    		dfs2(i,i);
    	}
    	for(int i=1;i<=k;i++){
    		x=read();y=read();
    		if(id[x]!=id[y])continue;
    		int lca=LCA(x,y);
    		add_que(x,y,lca,i);
    	}
    }
    int main(){
    	init();
    	work();
        return 0;
    }
    
  • 相关阅读:
    P2056 [ZJOI2007]捉迷藏
    P2993 [FJOI2014]最短路径树问题
    P4149 [IOI2011]Race 点分治
    P2634 [国家集训队]聪聪可可 点分治
    [APIO2008]免费道路
    [luogu4255]公主の#18文明游戏
    [ZJOI2010]基站选址
    [POI2011]Meteors
    [SCOI2015]国旗计划
    [BZOJ4373]算术天才⑨与等差数列
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9508385.html
Copyright © 2011-2022 走看看