1. 程式人生 > >Hihocoder1883 : 生成樹問題(並查集+樹剖+線段樹)

Hihocoder1883 : 生成樹問題(並查集+樹剖+線段樹)

描述

有一個無向圖,有n個點,m1條第一類邊和m2條第二類邊。第一類邊有邊權,第二類邊無邊權。請為第二類的每條邊定義一個邊權,使得第二類邊可能全部出現在該無向圖的最小生成樹上,同時要求第二類邊的邊權總和儘可能大。
注:第二類邊不會形成環

輸入

第一行三個數n,m2,m1

接下來m2行,每行兩個數,描述一條第二類邊,分別表示兩個端點接下來m1行,每行三個數,描述一條第一類邊,分別表示兩個端點和邊權

對於30%的資料,n ≤ 5

對於60%的資料,n ≤ 1000

對於100%的資料,1 ≤ n ≤ 100000, m1 ≤ 2 × n, m2 < n

輸出

輸出一個數,表示第二類邊的權值總和最大可能為多少。(若可能為無窮大則輸出-1)

樣例輸入
5 2 3
1 2
4 5
2 3 100
3 4 100
1 5 1000
樣例輸出
2000

 

思路:我們先把第二類(B)和第一類(A)按權值排序,生成一個最小生成樹,那麼,對於第一類裡面的那些沒有被加入到樹裡的邊e,我們需要保證這些邊的兩端在樹上的路徑e.u->e.v上的所有A類邊都不大於e.cost。

所以我們需要去更新A類邊的權值,我們把A類邊都的權值都設為inf,然後用e.cost去更新,更新的過程就是勢能線段樹,如果區間有inf,那麼就更新,否則跳過這個區間,因為每個A類邊最多被跟新一次,勢能會變小,這樣可以保證複雜度。

 (開始一直在想持久化並查集...趕腳做不出來,然後才寫了這個又長又臭的程式碼。求更簡單的方法。qwq

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=2000010;
const int inf=1e9;
int x[maxn],y[maxn],Laxt[maxn],Next[maxn],To[maxn],Len[maxn];
int fa[maxn],Mx[maxn],tot,N,cnt,dep[maxn];
int a[maxn],sz[maxn],son[maxn],Top[maxn],p[maxn],q[maxn]; struct in{ int u,v,cost; }s[maxn]; bool cmp(in p,in q){ return p.cost<q.cost;} int ff[maxn]; int find(int x){if(x==ff[x]) return x; return ff[x]=find(ff[x]);} void add(int u,int v,int c){ Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; Len[cnt]=c; } void dfs1(int u,int f){ dep[u]=dep[f]+1; fa[u]=f; sz[u]=1; for(int i=Laxt[u];i;i=Next[i]) if(To[i]!=f) { dfs1(To[i],u),sz[u]+=sz[To[i]]; a[To[i]]=Len[i]; if(sz[To[i]]>sz[son[u]]) son[u]=To[i]; } } void dfs2(int u,int top) { Top[u]=top; p[++tot]=u; q[u]=tot; if(son[u]) dfs2(son[u],top); for(int i=Laxt[u];i;i=Next[i]){ if(To[i]!=son[u]&&dep[To[i]]>dep[u]) dfs2(To[i],To[i]); } } void build(int Now,int L,int R) { if(L==R) { Mx[Now]=a[p[L]]; return ;} int Mid=(L+R)>>1; build(Now<<1,L,Mid); build(Now<<1|1,Mid+1,R); Mx[Now]=max(Mx[Now<<1],Mx[Now<<1|1]); } int query(int Now,int L,int R,int l,int r) { if(Mx[Now]<inf) return 0; if(L==R){Mx[Now]=0; return 1;} int Mid=(L+R)>>1,res=0; if(l<=Mid) res+=query(Now<<1,L,Mid,l,r); if(r>Mid) res+=query(Now<<1|1,Mid+1,R,l,r); Mx[Now]=max(Mx[Now<<1],Mx[Now<<1|1]); return res; } int Query(int u,int v) { int f1=Top[u],f2=Top[v],res=0; while(f1!=f2){ if(dep[f1]<dep[f2]) swap(f1,f2),swap(u,v); res+=query(1,1,N,q[f1],q[u]); u=fa[f1]; f1=Top[u]; } if(u!=v){ if(dep[u]>dep[v]) swap(u,v); res+=query(1,1,N,q[son[u]],q[v]); } return res; } int main() { int A,B; ll ans=0; scanf("%d%d%d",&N,&A,&B); rep(i,1,N) ff[i]=i; rep(i,1,A){ scanf("%d%d",&x[i],&y[i]); int fu=find(x[i]),fv=find(y[i]); ff[fu]=fv; add(x[i],y[i],inf); add(y[i],x[i],inf); } rep(i,1,B) scanf("%d%d%d",&s[i].u,&s[i].v,&s[i].cost); sort(s+1,s+B+1,cmp); rep(i,1,B) { int fu=find(s[i].u),fv=find(s[i].v); if(fu==fv) s[++tot]=s[i]; else { ff[fu]=fv; add(s[i].u,s[i].v,s[i].cost); add(s[i].v,s[i].u,s[i].cost); } } B=tot; tot=0; dfs1(1,0); dfs2(1,1); build(1,1,N); tot=0; rep(i,1,B){ tot=Query(s[i].u,s[i].v); ans+=(ll)tot*s[i].cost; } if(Mx[1]==inf) puts("-1"); else printf("%lld\n",ans); return 0; }