bzoj3669 [Noi2014]魔法森林
link cut tree
先把边按a排序,用并查集维护连通块,一条边一条边往里面加,1和n连通就更新答案
lct中需要维护当前链的边权最大值,把边权转化为点权:在边中间插一个点,边权赋值到点上
若当前边的b<max(u,v)就要先cut掉u~v路径上的b最大的边
1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cstdio> 6 #include<string> 7 #include<cmath> 8 #include<ctime> 9 #include<queue> 10 #include<stack> 11 #include<map> 12 #include<set> 13 #define rre(i,r,l) for(int i=(r);i>=(l);i--) 14 #define re(i,l,r) for(int i=(l);i<=(r);i++) 15 #define Clear(a,b) memset(a,b,sizeof(a)) 16 #define inout(x) printf("%d",(x)) 17 #define douin(x) scanf("%lf",&x) 18 #define strin(x) scanf("%s",(x)) 19 #define LLin(x) scanf("%lld",&x) 20 #define op operator 21 #define CSC main 22 typedef unsigned long long ULL; 23 typedef const int cint; 24 typedef long long LL; 25 using namespace std; 26 cint inf=2147483647; 27 void inin(int &ret) 28 { 29 ret=0;int f=0;char ch=getchar(); 30 while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();} 31 while(ch>='0'&&ch<='9')ret*=10,ret+=ch-'0',ch=getchar(); 32 ret=f?-ret:ret; 33 } 34 struct bian 35 { 36 int u,v,a,b; 37 void in(){inin(u),inin(v),inin(a),inin(b);} 38 bool op < (const bian &rhs)const {return a<rhs.a;} 39 }bi[100010]; 40 namespace lct 41 { 42 int ch[200020][2],w[200020],Max[200020],fa[200020],rev[200020]; 43 bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;} 44 void maintain(int x) 45 { 46 Max[x]=x; 47 if(w[Max[x]]<w[Max[ch[x][0]]])Max[x]=Max[ch[x][0]]; 48 if(w[Max[x]]<w[Max[ch[x][1]]])Max[x]=Max[ch[x][1]]; 49 } 50 void rotate(int x) 51 { 52 int y=fa[x],z=fa[y]; 53 if(!isroot(y))ch[z][ch[z][1]==y]=x; 54 fa[x]=z,fa[y]=x; 55 int d=ch[y][1]==x; 56 fa[ch[x][d^1]]=y; 57 ch[y][d]=ch[x][d^1]; 58 ch[x][d^1]=y; 59 maintain(y),maintain(x); 60 } 61 void down(int x) 62 { 63 if(rev[x]) 64 { 65 swap(ch[x][0],ch[x][1]); 66 rev[ch[x][0]]^=1; 67 rev[ch[x][1]]^=1; 68 rev[x]=0; 69 } 70 } 71 int sta[100010],top; 72 void splay(int x) 73 { 74 top=0;int xx=x;sta[++top]=xx; 75 while(!isroot(xx))sta[++top]=fa[xx],xx=fa[xx]; 76 while(top)down(sta[top--]); 77 while(!isroot(x)) 78 { 79 int y=fa[x],z=fa[y]; 80 if(!isroot(y)) 81 if((ch[y][1]==x)^(ch[z][1]==y))rotate(x); 82 else rotate(y);else ; 83 rotate(x); 84 } 85 } 86 void access(int x) 87 { 88 int temp=0; 89 while(x) 90 { 91 splay(x); 92 ch[x][1]=temp; 93 maintain(x); 94 temp=x,x=fa[x]; 95 } 96 } 97 void reverse(int x) 98 { 99 access(x),splay(x);rev[x]^=1; 100 } 101 void link(int x,int y) 102 { 103 reverse(x);fa[x]=y; 104 } 105 void cut(int x,int y) 106 { 107 reverse(x),access(y),splay(y),fa[x]=ch[y][0]=0;maintain(y); 108 } 109 int query(int x,int y) 110 { 111 reverse(x),access(y),splay(y); 112 return Max[y]; 113 } 114 } 115 int n,m,fa[200020]; 116 int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} 117 int main() 118 { 119 inin(n),inin(m);re(i,1,n)fa[i]=i; 120 re(i,1,m)bi[i].in();int ans=inf; 121 sort(bi+1,bi+m+1); 122 re(i,1,m) 123 { 124 int u=bi[i].u,v=bi[i].v,a=bi[i].a,b=bi[i].b; 125 if(find(u)==find(v)) 126 { 127 int temp=lct::query(u,v); 128 if(lct::w[temp]>b) 129 { 130 lct::cut(temp,bi[temp-n].u); 131 lct::cut(temp,bi[temp-n].v); 132 } 133 else 134 { 135 if(find(1)==find(n))ans=min(ans,a+lct::w[lct::query(1,n)]); 136 continue; 137 } 138 } 139 else fa[find(u)]=find(v); 140 lct::w[n+i]=b,lct::Max[n+i]=n+i; 141 lct::link(u,n+i),lct::link(v,n+i); 142 if(find(1)==find(n))ans=min(ans,a+lct::w[lct::query(1,n)]); 143 } 144 printf("%d\n",ans==inf?-1:ans); 145 return 0; 146 }