洛谷 2387 NOI2014魔法森林 LCT
【题解】
我们先把边按照$a$值从小到大排序,并按照这个顺序加边。
如果当前要加入的边连接的两点$u$与$v$已经是连通的,那么直接加入这条边就会出现环。这时我们需要删除这个环中$b$值最大的边。因此我们需要维护区间最大值,以及最大值的位置。
如果当前$1$与$n$已经连通,就更新$ans$,当前从$1~n$的代价是$ai+val[querymax(1,n)]$;
为了方便处理,我们可以把边开成点,即加边的时候多开一个表示这条边的点,在上面记录边权等信息。
1 #include<cstdio> 2 #include<algorithm> 3 #define N (500010) 4 #define inf (2e9) 5 #define ls (c[u][0]) 6 #define rs (c[u][1]) 7 using namespace std; 8 int n,m,ans; 9 inline int read(){ 10 int k=0,f=1; char c=getchar(); 11 while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar(); 12 while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar(); 13 return k*f; 14 } 15 struct edge{int u,v,a,b;}e[N]; 16 struct Link_cut_tree{ 17 int top,c[N][2],fa[N],rev[N],q[N],maxpos[N],val[N]; 18 inline void pushdown(int u){ 19 if(rev[u]) rev[ls]^=1,rev[rs]^=1,rev[u]^=1,swap(ls,rs); 20 } 21 inline void pushup(int u){ 22 maxpos[u]=u; 23 if(val[maxpos[ls]]>val[maxpos[u]]) maxpos[u]=maxpos[ls]; 24 if(val[maxpos[rs]]>val[maxpos[u]]) maxpos[u]=maxpos[rs]; 25 } 26 inline bool isroot(int u){ 27 return c[fa[u]][0]!=u&&c[fa[u]][1]!=u; 28 } 29 inline bool which(int u){ 30 return c[fa[u]][1]==u; 31 } 32 void rotate(int u){ 33 int f=fa[u],gf=fa[f],wh=which(u); 34 if(!isroot(f)) c[gf][which(f)]=u; 35 fa[u]=gf; fa[f]=u; fa[c[u][wh^1]]=f; 36 c[f][wh]=c[u][wh^1]; c[u][wh^1]=f; 37 pushup(f); pushup(u); 38 } 39 void splay(int u){ 40 q[top=1]=u; 41 for(int i=u;!isroot(i);i=fa[i]) q[++top]=fa[i]; 42 for(int i=top;i;i--) pushdown(q[i]); 43 while(!isroot(u)){ 44 if(!isroot(fa[u])) rotate(which(fa[u])==which(u)?fa[u]:u); 45 rotate(u); 46 } 47 pushup(u); 48 } 49 void access(int u){ 50 for(int son=0;u;son=u,u=fa[u]) splay(u),c[u][1]=son,pushup(u); 51 } 52 void makeroot(int u){ 53 access(u); splay(u); rev[u]^=1; 54 } 55 int find(int u){ 56 access(u); splay(u); 57 while(ls) u=ls; 58 return u; 59 } 60 void split(int x,int y){ 61 makeroot(x); access(y); splay(y); 62 } 63 void cut(int x,int y){ 64 split(x,y); 65 c[y][0]=fa[x]=0; 66 pushup(y); 67 } 68 void link(int x,int y){ 69 makeroot(x); fa[x]=y; 70 } 71 int query(int x,int y){ 72 makeroot(x); access(y); splay(y); 73 return maxpos[y]; 74 } 75 }t; 76 bool cmp(edge x,edge y){ 77 return x.a<y.a; 78 } 79 int main(){ 80 ans=inf; 81 n=read(); m=read(); 82 for(int i=1;i<=m;i++) 83 e[i].u=read(),e[i].v=read(),e[i].a=read(),e[i].b=read(); 84 sort(e+1,e+m+1,cmp); 85 for(int i=1;i<=m;i++){ 86 int u=e[i].u,v=e[i].v,a=e[i].a,b=e[i].b; 87 if(t.find(u)==t.find(v)){ 88 int pos=t.query(u,v); 89 if(t.val[pos]>b){ 90 t.cut(pos,e[pos-n].u); 91 t.cut(pos,e[pos-n].v); 92 } 93 else{ 94 if(t.find(1)==t.find(n)) ans=min(ans,a+t.val[t.query(1,n)]); 95 continue; 96 } 97 } 98 t.val[n+i]=b; t.maxpos[n+i]=n+i; 99 t.link(u,n+i); t.link(v,n+i); 100 if(t.find(1)==t.find(n)) ans=min(ans,a+t.val[t.query(1,n)]); 101 } 102 if(ans==inf) puts("-1"); 103 else printf("%d\n",ans); 104 return 0; 105 }