洛谷 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
",ans);
104     return 0;
105 }
View Code
原文地址:https://www.cnblogs.com/DriverLao/p/8277550.html