BZOJ 3732 Network Kruskal重構樹
阿新 • • 發佈:2019-01-23
題目大意:給定一個n個點m條邊的無向連通圖,k次詢問兩點之間所有路徑中最長邊的最小值
Kruskal+倍增LCA做法見http://blog.csdn.net/popoqqq/article/details/39755703
LCT做法見http://blog.csdn.net/popoqqq/article/details/39929277
Kruskal重構樹真是強大……一不小心手滑就RANK1啥的……
每加入一條邊時,我們並不連結這條邊的兩端點,而是把這條邊兩端點所在並查集的根連線起來,而且是按秩合併
這樣做的好處就是任何一個節點到根的路徑長度不超過logn
且由於Kruskal重構樹的性質,兩點之間的最長邊和原圖相同,且最長邊的一端連線的一定是兩點的LCA
於是直接暴力向上找就行 如果加上倍增的話或許能優化到O(loglogn)
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 15100 using namespace std; struct abcd{ int x,y,f; bool operator < (const abcd &Y) const { return f < Y.f ; } }edges[M<<1]; int n,m,k; int belong[M],fa[M],size[M],dis[M],dpt[M]; int Find(int x) { if(!belong[x]) belong[x]=x,size[x]=1; if(belong[x]==x) return x; return belong[x]=Find(belong[x]); } int Get_Depth(int x) { if(dpt[x]) return dpt[x]; if(!fa[x]) return dpt[x]=1; return dpt[x]=Get_Depth(fa[x])+1; } void Kruskal() { int i; sort(edges+1,edges+m+1); for(i=1;i<=m;i++) { int x=Find(edges[i].x); int y=Find(edges[i].y); if(x==y) continue ; if(size[x]>size[y]) swap(x,y); belong[x]=y; size[y]=max(size[y],size[x]+1); fa[x]=y; dis[x]=edges[i].f; } } int Query(int x,int y) { int re=0; if(dpt[x]<dpt[y]) swap(x,y); while(dpt[x]>dpt[y]) re=max(re,dis[x]),x=fa[x]; while(x!=y) re=max(re,dis[x]),re=max(re,dis[y]),x=fa[x],y=fa[y]; return re; } int main() { int i,x,y; cin>>n>>m>>k; for(i=1;i<=m;i++) scanf("%d%d%d",&edges[i].x,&edges[i].y,&edges[i].f); Kruskal(); for(i=1;i<=n;i++) Get_Depth(i); for(i=1;i<=k;i++) { scanf("%d%d",&x,&y); printf("%d\n", Query(x,y) ); } }