BZOJ3712 [PA2014]Fiolki [LCA]

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;
}

猜你喜欢

转载自blog.csdn.net/arliastark/article/details/80720110