bzoj 3669 [Noi2014]魔法森林
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3669
第二道LCT!
直接看TJ……https://blog.csdn.net/clove_unique/article/details/51317842
把连边表示成与点相连 是很好的。因为splay中的边变动得挺随意的。
感觉理解又加深了。那个query的部分,效果是x和y所在的辅助树中x深度最小、y深度最大,即当前辅助树就是x和y之间的链!
因为忘记在splay的最后pshp,RE(为什么是RE?)了好久。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int N=5e4+5,M=1e5+5,INF=0x7fffffff; int n,m,pre[N+M],mx[N+M],c[N+M][2],fa[N],stack[N+M],top,val[N+M],ans;//val // bool rev[N+M]; struct Ed{ int x,y,a,b; bool operator<(const Ed &k)const {return a<k.a;} }ed[M]; int find(int a){return fa[a]==a?a:fa[a]=find(fa[a]);} bool isroot(int x){return c[pre[x]][0]!=x&&c[pre[x]][1]!=x;} void pshp(int x) { mx[x]=x; if(val[mx[c[x][0]]]>val[mx[x]])mx[x]=mx[c[x][0]]; if(val[mx[c[x][1]]]>val[mx[x]])mx[x]=mx[c[x][1]]; } void reverse(int x) { if(rev[x]){ rev[c[x][0]]^=1;rev[c[x][1]]^=1; swap(c[x][0],c[x][1]); rev[x]=0; } } void rotate(int x) { int y=pre[x],z=pre[y],d=(x==c[y][1]); if(!isroot(y))c[z][y==c[z][1]]=x; pre[x]=z;pre[y]=x; c[y][d]=c[x][!d];pre[c[x][!d]]=y;c[x][!d]=y; pshp(y);pshp(x); } void splay(int x) { stack[top=1]=x; for(int t=x;!isroot(t);t=pre[t])stack[++top]=pre[t]; for(;top;top--)reverse(stack[top]); for(;!isroot(x);rotate(x)) { int y=pre[x],z=pre[y]; if(isroot(y))continue; ((c[y][0]==x)^(c[z][0]==y))?rotate(x):rotate(y); } pshp(x);////////// } void access(int x) { for(int t=0;x;c[x][1]=t,t=x,x=pre[x])splay(x); } void makeroot(int x) { access(x);splay(x);rev[x]^=1; } int query(int x,int y) { makeroot(x);access(y);splay(y);//y没有右儿子 //access之后相当于在辅助树中splay,故不用rev // printf("x=%d y=%d c[x][0]=%d c[x][1]=%d c[y][0]=%d c[y][1]=%d\n",x,y,c[x][0],c[x][1],c[y][0],c[y][1]); return mx[y]; //x和y之间的不应该是x的右儿子? // int vmx=mx[c[x][1]]; //此时应该是y为根、无右儿子;x为y的左儿子,无左儿子。故。 // if(val[vmx]<val[x])vmx=x; //但为什么这样写不行? // if(val[vmx]<val[y])vmx=y; //y的左儿子可能不是x。在access的splay中,x可能在自己的辅助树中被转走 // return vmx; //但makert(x)使x变成深度最小的,access(y)使y变成深度最大的,故此时辅助树中只有链上的。 } void link(int x,int y) { makeroot(x);pre[x]=y;//此时不用pshp--query的时候会弄好 } void cut(int x,int y) { query(x,y); pre[x]=0;c[y][0]=0; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%d%d",&ed[i].x,&ed[i].y,&ed[i].a,&ed[i].b); sort(ed+1,ed+m+1); for(int i=1;i<=n;i++)fa[i]=i; ans=INF; for(int i=1;i<=m;i++) { int u=ed[i].x,v=ed[i].y;val[i+n]=ed[i].b;//val应记录排序后的 if(find(u)!=find(v)){ fa[find(u)]=find(v); link(i+n,u);link(i+n,v); if(find(1)==find(n))ans=min(ans,ed[i].a+val[query(1,n)]); } else{ query(u,v);int k=mx[v];if(val[k]<val[i+n])continue;// cut(k,ed[k-n].x);cut(k,ed[k-n].y); link(i+n,u);link(i+n,v); if(find(1)==find(n))ans=min(ans,ed[i].a+val[query(1,n)]); //这里+val[query(1,n)],不是val[i+n] } } printf("%d",(ans==INF?-1:ans)); return 0; }