BZOJ3712 [PA2014]Fiolki [LCA]
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
解法
真是一道很劲的题,感谢Newuser大佬三两句话把我讲懂OwO.
在BZOJ上水过了,在NKOJ上TLE了无数次之后才水过= =
原因是我把所有的int换成了long long,而实际上只需要int就足够了,最后Ans用long long即可。
错误的解法
直接把反应的步骤连边,遇到可以反应的物质就判断这两种物质在不在一张图里。
这当然是极其标准的错误解法,因为这样完全没有考虑反应在时间上的先后顺序。
正确的解法
如果两个反应发生,要考虑两点:①反应发生的时间,②反应的优先程度。并且要先考虑①,再考虑②。
反应时间可以通过LCA解决:每两个反应连在一个新的点上,这个点就代表了这两种物质,两种物质的LCA的深度就是它们反应时间的先后顺序。比如共有3个瓶子、2个反应,1和2先混合,那么就把1、2连在4号节点上,如果3再和2混合,那么就把3和4连在5号节点上;1与3的LCA是5,深度为1,相当于它们最后混合在一起。
最后sort一下就可以了。
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define E 800100
using namespace std;
struct node{
int x,y,dep,pri;
bool operator<(const node &a)const{
if(dep==a.dep)return pri<a.pri;
return dep>a.dep;
}
}nod[E];
int End[E],Next[E],Last[E],Log[E],tot;
void Ins(int x,int y){
End[++tot]=y,Next[tot]=Last[x],Last[x]=tot;
}
int Fa[E][20],D[E],G[E],_Fa[E],Dfn[E];
void DFS(int u,int x){
D[u]=D[Fa[u][0]]+1,Dfn[u]=x;
int s=Log[D[u]];
for(int i=1;i<=s;i++)Fa[u][i]=Fa[Fa[u][i-1]][i-1];
for(int i=Last[u];i;i=Next[i]){Fa[End[i]][0]=u;DFS(End[i],x);}
}
int LCA(int x,int y){
if(D[x]<D[y])swap(x,y);
int s=ceil(log2(D[x]));int d=D[x]-D[y];
for(int i=0;i<=s;i++)
if(d&(1<<i))x=Fa[x][i];
if(x==y)return x;
for(int i=s;i>=0;i--)
if(Fa[x][i]!=Fa[y][i])x=Fa[x][i],y=Fa[y][i];
return Fa[x][0];
}
int main(){
int n,m,k;scanf("%d%d%d",&n,&m,&k);
Log[0]=-1;
for(int i=1;i<E;i++)Log[i]=Log[i>>1]+1;
for(int i=1;i<=n;i++)scanf("%d",&G[i]);
for(int i=1;i<E;i++)_Fa[i]=i;
int Root=n;
for(int i=1;i<=m;i++){
int x,y;scanf("%d%d",&x,&y);
Root++;
Ins(Root,_Fa[x]),Ins(Root,_Fa[y]);
_Fa[y]=Root;
}
for(int i=Root;i;i--)if(!Fa[i][0])DFS(i,i);
int cnt=0;
for(int i=1;i<=k;i++){
int tx,ty;
scanf("%d%d",&tx,&ty);
if(Dfn[tx]==Dfn[ty])nod[++cnt]=(node){tx,ty,D[LCA(tx,ty)],i};
}
sort(nod+1,nod+cnt+1);
long long Ans=0;
for(int i=1;i<=cnt;i++){
int m=min(G[nod[i].x],G[nod[i].y]);
G[nod[i].x]-=m,G[nod[i].y]-=m,Ans+=m;
}
printf("%lld",Ans<<1LL);return 0;
}