【NOI2014】魔法森林
题面
https://www.luogu.org/problem/P2387
题解
双关键字讨论处理,直接固定一个关键字枚举第二个即可。
$LCT$维护边上信息,拆边。
#include<cstdio> #include<iostream> #include<algorithm> #define ri register int #define N 50500 #define M 100500 int n,m; int stk[N+M]; int top,ans; using namespace std; struct cut{ int u,v,a,b; bool operator < (const cut& rhs) const { return a<rhs.a; } } e[M]; struct binchaji{ int f[N]; void clear() { for (ri i=1;i<=n;i++) f[i]=i; } int findroot(int x) { if (f[x]==x) return x; return f[x]=findroot(f[x]); } void merge(int u,int v) { f[u]=v; } } set; struct link_cut_tree{ int b[N+M],poi[N+M]; int f[N+M],ch[N+M][2]; bool rev[N+M]; bool opt(int x) { return ch[f[x]][1]==x; } bool notroot(int x) { return ch[f[x]][0]==x || ch[f[x]][1]==x; } void update(int x) { poi[x]=x; if (ch[x][0] && b[poi[ch[x][0]]]>b[poi[x]]) poi[x]=poi[ch[x][0]]; if (ch[x][1] && b[poi[ch[x][1]]]>b[poi[x]]) poi[x]=poi[ch[x][1]]; } void rotate(int x) { int y=f[x],z=f[y],s=opt(x),w=ch[x][1^s]; f[x]=z; if (notroot(y)) ch[z][opt(y)]=x; ch[y][s]=w; if (w) f[w]=y; f[y]=x; ch[x][1^s]=y; update(y); update(x); } void pushr(int x) { if (!rev[x]) return; rev[x]=0; 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; } void splay(int x) { int y=x; top=0; while (notroot(y)) stk[++top]=y,y=f[y]; stk[++top]=y; while (top) pushr(stk[top]),top--; while (notroot(x)) { if (!notroot(f[x])) rotate(x); else { if (opt(x)==opt(f[x])) rotate(f[x]); else rotate(x); rotate(x); } } } void access(int x) { int y=0; while (x) { splay(x); ch[x][1]=y; update(x); y=x; x=f[x]; } } void makeroot(int x) { access(x); splay(x); rev[x]^=1; pushr(x); } void link(int x,int y) { makeroot(x); f[x]=y; } void cut(int x,int y) { makeroot(x); access(y); splay(y); ch[y][opt(x)]=f[x]=0; update(y); } int query(int x,int y) { makeroot(x); access(y); splay(y); return poi[y]; } } lct; void add_edge(int x) { lct.link(e[x].u,x+n); lct.link(e[x].v,x+n); } void del_edge(int x) { lct.cut(e[x].u,x+n); lct.cut(e[x].v,x+n); } void update(int cur){ int p=lct.query(1,n); if (lct.b[p]+e[cur].a<ans) ans=lct.b[p]+e[cur].a; } int main(){ scanf("%d %d",&n,&m); for (ri 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+m+1); for (ri i=1;i<=m;i++) { lct.b[n+i]=e[i].b; lct.poi[n+i]=n+i; } set.clear(); ans=987654321; for (ri i=1;i<=m;i++) if (e[i].u!=e[i].v) { int root1=set.findroot(e[i].u),root2=set.findroot(e[i].v); if (root1!=root2) { set.merge(root1,root2); add_edge(i); if (set.findroot(1)==set.findroot(n)) update(i); } else { int poi=lct.query(e[i].u,e[i].v); if (lct.b[poi]>e[i].b) { del_edge(poi-n); add_edge(i); if (set.findroot(1)==set.findroot(n)) update(i); } } } if (ans==987654321) puts("-1"); else cout<<ans<<endl; }