BZOJ3732:Network(LCT与最小生成树)
给你N个点的无向图 (1 <= N <= 15,000),记为:1…N。 图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 < = d_j < = 1,000,000,000). 现在有 K个询问 (1 < = K < = 20,000)。 每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少? Input 第一行: N, M, K。 第2..M+1行: 三个正整数:X, Y, and D (1 <= X <=N; 1 <= Y <= N). 表示X与Y之间有一条长度为D的边。 第M+2..M+K+1行: 每行两个整数A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少? Output 对每个询问,输出最长的边最小值是多少。 Sample Input 6 6 8 1 2 5 2 3 4 3 4 3 1 4 8 2 5 7 4 6 2 1 2 1 3 1 4 2 3 2 4 5 1 6 2 6 1 Sample Output 5 5 5 4 4 7 4 5 Hint 1 <= N <= 15,000 1 <= M <= 30,000 1 <= d_j <= 1,000,000,000 1 <= K <= 15,000
题意:给定N点M边的无向图,每边有权值,Q次询问,每次询问给出u、v,回答u到v的所有路径中最大边的最小值。
思路:常识可知,需要最小生成树,然后就是最小生成树两点间的最大值。
可以用树剖+线段树解决 。或者动态树LCT姿势搞定。
(写LCT写惯了就不想写树剖了有没有
#include<cstdio> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; const int maxn=50010; struct egde{ int x,y,val; }e[maxn]; void read(int &x){ char c=getchar(); x=0; for(;c>'9'||c<'0';c=getchar()); for(;c<='9'&&c>='0';c=getchar()) x=(x<<3)+(x<<1)+c-'0'; } struct LCT { int Max[maxn],rev[maxn],ch[maxn][2],fa[maxn],stc[maxn],top; int isroot(int x){ return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x; } int get(int x){ return ch[fa[x]][1]==x; } void pushdown(int x) { if(!rev[x]||!x) return ; swap(ch[x][0],ch[x][1]); if(ch[x][0]) rev[ch[x][0]]^=1; if(ch[x][1]) rev[ch[x][1]]^=1; rev[x]=0; } void pushup(int x) { Max[x]=x; if(ch[x][0]&&e[Max[ch[x][0]]].val>e[Max[x]].val) Max[x]=Max[ch[x][0]]; if(ch[x][1]&&e[Max[ch[x][1]]].val>e[Max[x]].val) Max[x]=Max[ch[x][1]]; } void rotate(int x) { int old=fa[x],fold=fa[old],opt=get(x); if(!isroot(old)) ch[fold][get(old)]=x; fa[x]=fold; ch[old][opt]=ch[x][opt^1]; fa[ch[old][opt]]=old; ch[x][opt^1]=old; fa[old]=x; pushup(old); pushup(x); } void splay(int x) { int top=0; stc[++top]=x; for(int i=x;!isroot(i);i=fa[i]) stc[++top]=fa[i]; for(int i=top;i;i--) pushdown(stc[i]); for(int f;!isroot(x);rotate(x)){ if(!isroot(f=fa[x])) rotate(get(x)==get(f)?f:x); } } void access(int x) { int rson=0; for(;x;rson=x,x=fa[x]){ splay(x); ch[x][1]=rson; pushup(x); } } int find(int x){ access(x); splay(x); while(ch[x][0]) x=ch[x][0]; return x;} int query(int x,int y) { make_root(y); access(x); splay(x); return Max[x]; } void make_root(int x) { access(x); splay(x); rev[x]^=1; } void link(int x,int y) { make_root(x); fa[x]=y; splay(x); } void cut(int x,int y) { make_root(x); access(y); splay(y); fa[x]=ch[y][0]=0; } }S; int main() { int N,M,Q,u,v,i; scanf("%d%d%d",&N,&M,&Q); for(i=1;i<=M;i++){ read(e[i].x); read(e[i].y) ;read(e[i].val); if(S.find(M+e[i].x)!=S.find(M+e[i].y)){ S.link(i,M+e[i].x); S.link(i,M+e[i].y); } else { int tmp=S.query(M+e[i].x,M+e[i].y); if(e[tmp].val>e[i].val){ S.cut(tmp,M+e[tmp].x); S.cut(tmp,M+e[tmp].y); S.link(i,M+e[i].x); S.link(i,M+e[i].y); } } } while(Q--){ read(u); read(v); printf("%d\n",e[S.query(M+u,M+v)].val); } return 0; }
It is your time to fight!