对合并过程建树。然后只需要按照时间顺序考虑每个反应就行了,时间顺序根据lca的深度确定。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 200010 #define M 500010 #define ll long long int n,m,k,a[N],p[N<<1],fa[N<<1],f[N<<1][20],deep[N<<1],t=0; ll ans=0; struct data{int to,nxt; }edge[N<<1]; struct data2{int x,y,lca,i; }q[M]; int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} void dfs(int k) { for (int i=p[k];i;i=edge[i].nxt) { f[edge[i].to][0]=k; deep[edge[i].to]=deep[k]+1; dfs(edge[i].to); } } int lca(int x,int y) { if (deep[x]<deep[y]) swap(x,y); for (int j=19;~j;j--) if (deep[f[x][j]]>=deep[y]) x=f[x][j]; if (x==y) return x; for (int j=19;~j;j--) if (f[x][j]!=f[y][j]) x=f[x][j],y=f[y][j]; return f[x][0]; } bool cmp(const data2&a,const data2&b) { return deep[a.lca]>deep[b.lca]||deep[a.lca]==deep[b.lca]&&a.i<b.i; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj3712.in","r",stdin); freopen("bzoj3712.out","w",stdout); const char LL[]="%I64d "; #else const char LL[]="%lld "; #endif n=read(),m=read(),k=read(); for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<=n+m;i++) fa[i]=i; for (int i=1;i<=m;i++) { int x=read(),y=read(); int p=find(x),q=find(y); fa[p]=fa[q]=n+i; addedge(n+i,p),addedge(n+i,q); } for (int i=n+m;i;i--) if (!f[i][0]) f[i][0]=i,dfs(i); for (int j=1;j<20;j++) for (int i=1;i<=n+m;i++) f[i][j]=f[f[i][j-1]][j-1]; for (int i=1;i<=k;i++) q[i].x=read(),q[i].y=read(),q[i].lca=lca(q[i].x,q[i].y),q[i].i=i; sort(q+1,q+k+1,cmp); for (int i=1;i<=k;i++) if (find(q[i].x)==find(q[i].y)) { int x=min(a[q[i].x],a[q[i].y]); ans+=x<<1;a[q[i].x]-=x,a[q[i].y]-=x; } cout<<ans; return 0; }