洛谷2387 BZOJ3669魔法森林题解
这道题被很多人用spfa水了过去,表示很。。。
其实spfa很好卡,这组数据可以卡掉大多数spfa
链接:密码:rjvk
这里讲一下LCT的做法
我们按照a将边排序,然后依次添加
每次加入时若两边没有联通,就直接加入,否则就
检查两边的路径中权值b最大的权值是多少,如果大于当前加入边的权值
就将该边删掉,然后将当前边加入
注意lct维护边权时需要用到拆点
# include<iostream> # include<algorithm> # include<cmath> # include<cstring> # include<cstdio> using namespace std; const int mn = 150005; const int inf = 2147483647; struct edge{int u,v,a,b;}; edge e[mn]; bool cmp(const edge &x,const edge &y) { if(x.a==y.a) return x.b<y.b; else return x.a<y.a; } int n,m,ans,fa[mn]; int _find(int x) {return x==fa[x] ? x : fa[x]=_find(fa[x]);} struct LCT{ int val[mn],fa[mn],c[mn][2],mx[mn],st[mn]; //mx[x]表示子树中权值最大的点的编号 bool rev[mn]; bool nroot(int x) { return c[fa[x]][0]==x || c[fa[x]][1]==x; } void zhuan(int x) { swap(c[x][1],c[x][0]); rev[x]^=1; } void pushdown(int x) { if(rev[x]) { rev[x]=0; if(c[x][0]) zhuan(c[x][0]); if(c[x][1]) zhuan(c[x][1]); } } void updown(int x) { mx[x]=x; if(c[x][0]) { if(val[mx[c[x][0]]]>val[mx[x]]) mx[x]=mx[c[x][0]]; } if(c[x][1]) { if(val[mx[c[x][1]]]>val[mx[x]]) mx[x]=mx[c[x][1]]; } } void rotate(int x) { int y=fa[x],z=fa[y],flag; if(c[y][0]==x) flag=1; else flag=0; if(nroot(y)) { if(c[z][0]==y) c[z][0]=x; else c[z][1]=x; } c[y][flag^1]=c[x][flag],fa[c[x][flag]]=y; c[x][flag]=y; fa[y]=x,fa[x]=z; updown(y); updown(x); } void splay(int x) { int top=0; st[++top]=x; for(int i=x;nroot(i);i=fa[i]) st[++top]=fa[i]; for(;top;top--) pushdown(st[top]); while(nroot(x)) { int y=fa[x],z=fa[y]; if(nroot(y)) { if((c[y][0]==x) ^ (c[z][0]==y)) rotate(x); else rotate(y); } rotate(x); } updown(x); } void access(int x) { int t=0; while(x){splay(x);c[x][1]=t;updown(x);t=x;x=fa[x];} } void makeroot(int x) { access(x); splay(x); zhuan(x); } void link(int x,int y) { makeroot(x); fa[x]=y; } void cut(int x,int y) { makeroot(x); access(y); splay(y); c[y][0]=fa[x]=0; updown(y); } int query(int x,int y) { makeroot(x); access(y); splay(y); return mx[y]; } }T; void pre() { for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++) T.val[i+n]=e[i].b; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].a,&e[i].b); sort(e+1,e+1+m,cmp); ans=inf; pre(); /* for(int i=1;i<=m;i++) printf("%d %d\n",e[i].a,e[i].b);*/ for(int i=1;i<=m;i++) { int x=e[i].u,y=e[i].v; int xx=_find(x),yy=_find(y); if(xx!=yy) { fa[xx]=yy; T.link(x,i+n); T.link(i+n,y); } else { int k=T.query(x,y); if(T.val[k]>e[i].b) { T.cut(e[k-n].u,k); T.cut(k,e[k-n].v); T.link(x,i+n); T.link(i+n,y); } } if(_find(1)==_find(n)) ans=min(ans,e[i].a+T.val[T.query(1,n)]); // printf("%d %d\n",e[i].a,T.query(1,n)); } if(ans==inf) printf("-1"); else printf("%d",ans); return 0; }