生活随笔
收集整理的這篇文章主要介紹了
【BZOJ3712】Fiolki(并查集重构树)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
【BZOJ3712】Fiolki(并查集重構(gòu)樹)
題面
BZOJ
題解
很神仙的題目。
我們發(fā)現(xiàn)所有的合并關(guān)系構(gòu)成了一棵樹。
那么兩種不同的東西如果產(chǎn)生反應(yīng),一定在兩個聯(lián)通塊恰好聯(lián)通的時候反應(yīng)。
那么,我們按照并查集的合并順序,類似于克魯斯卡爾重構(gòu)樹的方法構(gòu)建一個并查集重構(gòu)樹,
發(fā)現(xiàn)所有的反應(yīng)恰好在兩者的\(LCA\)處發(fā)生,
所以把所有可以發(fā)生的翻譯拿出來,
按照\(LCA\)的深度為第一關(guān)鍵字,反應(yīng)的優(yōu)先級為第二關(guān)鍵字排序。
然后按順序依次計算答案就好了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define ll long long
#define RG register
#define MAX 500500
inline int read()
{RG int x=0,t=1;RG char ch=getchar();while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();if(ch=='-')t=-1,ch=getchar();while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();return x*t;
}
ll ans;
int n,m,g[MAX],k;
struct Line{int v,next;}e[MAX];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int size[MAX],hson[MAX],top[MAX],fa[MAX],dep[MAX];
void dfs1(int u,int ff)
{dep[u]=dep[ff]+1;fa[u]=ff;size[u]=1;for(int i=h[u];i;i=e[i].next){int v=e[i].v;if(v==ff)continue;dfs1(v,u);size[u]+=size[v];if(size[v]>size[hson[u]])hson[u]=v;}
}
void dfs2(int u,int tp)
{top[u]=tp;if(hson[u])dfs2(hson[u],tp);for(int i=h[u];i;i=e[i].next)if(e[i].v!=hson[u]&&e[i].v!=fa[u])dfs2(e[i].v,e[i].v);
}
int LCA(int u,int v)
{while(top[u]^top[v])dep[top[u]]<dep[top[v]]?v=fa[top[v]]:u=fa[top[u]];return dep[u]<dep[v]?u:v;
}
int f[MAX],tot;
struct Event{int dep,id,u,v;}p[MAX];
bool operator<(Event a,Event b)
{if(a.dep!=b.dep)return a.dep>b.dep;return a.id<b.id;
}
int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);}
int main()
{n=read();m=read();k=read();for(int i=1;i<=n;++i)g[i]=read(),f[i]=i;for(int i=1;i<=m;++i){int a=read(),b=read();Add(n+i,f[getf(a)]);Add(n+i,f[getf(b)]);f[getf(a)]=f[getf(b)]=n+i;f[n+i]=n+i;}for(int i=n+m;i;--i)if(!dep[i])dfs1(i,0),dfs2(i,i);for(int i=1;i<=k;++i){int u=read(),v=read();if(getf(u)!=getf(v))continue;int s=LCA(u,v);p[++tot]=(Event){dep[s],i,u,v};}sort(&p[1],&p[tot+1]);for(int i=1;i<=tot;++i){int u=p[i].u,v=p[i].v;int s=min(g[u],g[v]);ans+=s;g[u]-=s;g[v]-=s;}printf("%lld\n",ans+ans);
}
轉(zhuǎn)載于:https://www.cnblogs.com/cjyyb/p/9368629.html
總結(jié)
以上是生活随笔為你收集整理的【BZOJ3712】Fiolki(并查集重构树)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。