zoukankan      html  css  js  c++  java
  • Link-Cut-Tree 题目总结

    P3690 【模板】Link Cut Tree (动态树)

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i>=(b);--i)
    #define ll long long
    #define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
    #define inf 0x3f3f3f3f
    #define CLR(A,v)  memset(A,v,sizeof A)
    //////////////////////////////////
    const int N=2e6+10;
    int fa[N],val[N],sum[N],son[N][2],rev[N],st[N];
    int get(int x){return son[fa[x]][0]==x||son[fa[x]][1]==x;}
    void up(int x){sum[x]=sum[son[x][1]]^sum[son[x][0]]^val[x];}
    void change(int x){swap(son[x][0],son[x][1]);rev[x]^=1;}
    void down(int x)
    {   
        if(!rev[x])return ;
        rev[x]=0;
        if(son[x][0])change(son[x][0]);
        if(son[x][1])change(son[x][1]);
    }
    void rotate(int x)
    {
        int y=fa[x],z=fa[y],k=son[fa[x]][1]==x,w=son[x][k^1];
        if(get(y))son[z][son[z][1]==y]=x;son[x][k^1]=y;son[y][k]=w;
        if(w)fa[w]=y;fa[y]=x;fa[x]=z;
        up(y);up(x);
    }
    void splay(int x)
    {
        int y=x,top=0;st[++top]=y;
        while(get(y))st[++top]=y=fa[y];
        while(top)down(st[top--]);
        while(get(x))
        {
            int y=fa[x],z=fa[y];
            if(get(y))
            rotate((son[y][0]==x)^(son[z][0]==y)?x:y);
            rotate(x);
        }up(x);
    }
    void access(int x)
    {   
        for(int y=0;x;x=fa[y=x])
        splay(x),son[x][1]=y,up(x);
    }
    void makeroot(int x)
    {
        access(x);splay(x);change(x);
    }
    int findroot(int x)
    {
        access(x);splay(x);
        while(son[x][0])down(x),x=son[x][0];
        splay(x);return x;
    }
    void split(int x,int y)
    {
        makeroot(x);access(y);splay(y);
    }
    void link(int x,int y)
    {
        makeroot(x);if(findroot(y)!=x)fa[x]=y;
    }
    void cut(int x,int y)
    {
        split(x,y);
        if(findroot(y)==x&&fa[y]==x&&!son[y][0])
        fa[y]=son[x][1]=0,up(x);
    }int n,m,x,y,op;
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&val[i]);
        while(m--)
        {
            scanf("%d%d%d",&op,&x,&y);
            if(op==0)split(x,y),printf("%d
    ",sum[y]);
            if(op==1)link(x,y);
            if(op==2)cut(x,y);
            if(op==3)splay(x),val[x]=y;//这里不up也没事 反正问的时候也会up
        }
        return 0;
    }
    View Code

    维护联通:

    P2147 [SDOI2008]洞穴勘测

    题意: 就是可删除的并查集

    题解: 没啥好说的 比模板简单

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i>=(b);--i)
    #define ll long long
    #define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
    #define inf 0x3f3f3f3f
    #define CLR(A,v)  memset(A,v,sizeof A)
    ////////////////////////////////////
    const int N=2e6+10;
    int fa[N],son[N][2],rev[N],st[N];
    int get(int x){return son[fa[x]][0]==x||son[fa[x]][1]==x;}
    void change(int x){swap(son[x][1],son[x][0]);rev[x]^=1;}
    void down(int x)
    {
        if(!rev[x])return ;
        rev[x]=0;
        if(son[x][1])change(son[x][1]);
        if(son[x][0])change(son[x][0]);
    }
    void rotate(int x)
    {
        int y=fa[x],z=fa[y],k=son[fa[x]][1]==x,w=son[x][k^1];
        if(get(y))son[z][son[z][1]==y]=x;son[x][k^1]=y;son[y][k]=w;
        if(w)fa[w]=y;fa[y]=x;fa[x]=z;
    }
    void splay(int x)
    {   
        int y=x,top=0;st[++top]=y;
        while(get(y))st[++top]=y=fa[y];
        while(top)down(st[top--]);
    
        while(get(x))
        {
            int y=fa[x],z=fa[y];
            if(get(y))
            rotate((son[y][0]==x)^(son[z][0]==y)?x:y);
            rotate(x);
        }
    }
    void access(int x)
    {
        for(int y=0;x;x=fa[y=x])
        splay(x),son[x][1]=y;
    }
    void makeroot(int x)
    {
        access(x);splay(x);change(x);
    }
    int findroot(int x)
    {
        access(x);splay(x);
        while(son[x][0])down(x),x=son[x][0];
        splay(x);return x;
    }
    void split(int x,int y)
    {
        makeroot(x);access(y);splay(y);
    }
    void link(int x,int y)
    {
        makeroot(x);
        if(findroot(y)!=x)fa[x]=y;
    }
    bool judge(int x,int y)
    {
        makeroot(x);
        return findroot(y)==x;
    }
    void cut(int x,int y)
    {
        split(x,y); 
        if(findroot(y)==x&&fa[y]==x&&!son[y][0])
        fa[y]=son[x][1]=0;
    }char s[100];int n,m,x,y;
    int main()
    {
        scanf("%d%d",&n,&m);
        while(m--)
        {
            scanf("%s %d%d",s,&x,&y);
            if(s[0]=='Q')printf("%s
    ",judge(x,y)?"Yes":"No");
            if(s[0]=='C')link(x,y);
            if(s[0]=='D')cut(x,y);
        }
        return 0;
    }
    View Code

    P3950 部落冲突 

    题解: 最无脑的lct  和上面那题有得一拼 

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
    #define inf 0x3f3f3f3f
    ////////////////////////////////////
    const int N=2e6+10;
    int fa[N],son[N][2],rev[N],st[N];
    int get(int x){return son[fa[x]][0]==x||son[fa[x]][1]==x;}
    void change(int x){swap(son[x][1],son[x][0]);rev[x]^=1;}
    void down(int x)
    {
        if(!rev[x])return ;
        rev[x]=0;
        if(son[x][1])change(son[x][1]);
        if(son[x][0])change(son[x][0]);
    }
    void rotate(int x)
    {
        int y=fa[x],z=fa[y],k=son[fa[x]][1]==x,w=son[x][k^1];
        if(get(y))son[z][son[z][1]==y]=x;son[x][k^1]=y;son[y][k]=w;
        if(w)fa[w]=y;fa[y]=x;fa[x]=z;
    }
    void splay(int x)
    {   
        int y=x,top=0;st[++top]=y;
        while(get(y))st[++top]=y=fa[y];
        while(top)down(st[top--]);
    
        while(get(x))
        {
            int y=fa[x],z=fa[y];
            if(get(y))
            rotate((son[y][0]==x)^(son[z][0]==y)?x:y);
            rotate(x);
        }
    }
    void access(int x)
    {
        for(int y=0;x;x=fa[y=x])
        splay(x),son[x][1]=y;
    }
    void makeroot(int x)
    {
        access(x);splay(x);change(x);
    }
    int findroot(int x)
    {
        access(x);splay(x);
        while(son[x][0])down(x),x=son[x][0];
        splay(x);return x;
    }
    void split(int x,int y)
    {
        makeroot(x);access(y);splay(y);
    }
    void link(int x,int y)
    {
        makeroot(x);
        if(findroot(y)!=x)fa[x]=y;
    }
    bool judge(int x,int y)
    {
        makeroot(x);
        return findroot(y)==x;
    }
    void cut(int x,int y)
    {
        split(x,y); 
        if(findroot(y)==x&&fa[y]==x&&!son[y][0])
        fa[y]=son[x][1]=0;
    }char s[100];int n,m,x,y;
    int a[N],b[N],cnt;
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<n;i++)scanf("%d%d",&x,&y),link(x,y);
        while(m--)
        {
            scanf("%s",s+1);
            if(s[1]=='Q')scanf("%d%d",&x,&y),printf("%s
    ",judge(x,y)?"Yes":"No");
            if(s[1]=='C')scanf("%d%d",&x,&y),a[++cnt]=x,b[cnt]=y,cut(x,y);
            if(s[1]=='U')scanf("%d",&x),link(a[x],b[x]);
        }
        return 0;
    }
    View Code

    维护链信息:

    P3203 [HNOI2010]弹飞绵羊

    题意: 一条直线上摆放着n个装置 每个装置有一个弹性系数k   表示在这个装置上会弹到这个装置后面的第k个装置上  如果不存在 那么弹上天

          操作一: 问从i开始弹 弹多少次上天

       操作二: 将第i装置的弹性系数改为x

    题解: lct板子题 连一下就行了

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i>=(b);--i)
    #define ll long long
    #define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
    #define inf 0x3f3f3f3f
    #define CLR(A,v)  memset(A,v,sizeof A)
    ////////////////////////////////////
    const int N=2e6+10;
    int fa[N],siz[N],son[N][2],rev[N],st[N];
    int get(int x){return son[fa[x]][1]==x||son[fa[x]][0]==x;}
    void up(int x){siz[x]=siz[son[x][1]]+siz[son[x][0]]+1;}
    void change(int x){swap(son[x][1],son[x][0]);rev[x]^=1;}
    void down(int x)
    {
        if(!rev[x])return ;rev[x]=0;
        if(son[x][0])change(son[x][0]);
        if(son[x][1])change(son[x][1]);
    }
    void rotate(int x)
    {
        int y=fa[x],z=fa[y],k=son[fa[x]][1]==x,w=son[x][k^1];
        if(get(y))son[z][son[z][1]==y]=x;son[x][k^1]=y;son[y][k]=w;
        if(w)fa[w]=y;fa[y]=x;fa[x]=z;
        up(y);up(x);
    }
    void splay(int x)
    {
        int y=x,top=0;st[++top]=y;
        while(get(y))st[++top]=y=fa[y];
        while(top)down(st[top--]);
        while(get(x))
        {
            int y=fa[x],z=fa[y];
            if(get(y))rotate((son[y][0]==x)^(son[z][0]==y)?x:y);
            rotate(x);
        }up(x);
    }
    void access(int x)
    {
        for(int y=0;x;x=fa[y=x])
        splay(x),son[x][1]=y,up(x);
    }
    void makeroot(int x)
    {
        access(x);splay(x);change(x);
    }
    int findroot(int x)
    {
        access(x);splay(x);
        while(son[x][0])down(x),x=son[x][0];
        splay(x);return x;
    }
    void split(int x,int y)
    {
        makeroot(x);access(y);splay(y);
    }
    void link(int x,int y)
    {
        makeroot(x);if(findroot(y)!=x)fa[x]=y;
    }
    void cut(int x,int y)
    {
        split(x,y);
        if(findroot(y)==x&&fa[y]==x&&!son[y][0])
        fa[y]=son[x][1]=0,up(x);
    }int n,m,op,x,y,z;
    int to[N];
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);link(i,min(n+1,i+x));to[i]=min(n+1,i+x);
        }
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d",&op);
            if(op==1){   scanf("%d",&x);x++;split(x,n+1);printf("%d
    ",siz[n+1]-1);}
            else {scanf("%d%d",&x,&y);x++;cut(x,to[x]);link(x,min(n+1,x+y));to[x]=min(n+1,x+y);}
        }
        return 0;
    }
    View Code

    P2486 [SDOI2011]染色

     题解: 之前用树剖做过一次  树剖维护区间合并非常的麻烦!   这题可以用lct快速水过   因为lct是将链上所有信息扔到splay里 所以直接输出即可

         注意对一段链区间更新信息的时候 和询问一样要split一下  然后对y也就是树根更新一下  然后down下去即可

    不过相比树剖  lct的常数确实有点大  时间慢了三倍。。

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
    #define inf 0x3f3f3f3f
    const int N=2e6+10;
    int fa[N],t[N],son[N][2],rev[N],st[N],col[N],lcol[N],rcol[N],tag[N];
    int get(int x){return son[fa[x]][0]==x||son[fa[x]][1]==x;}
    void up(int x)
    {
        if(son[x][0])lcol[x]=lcol[son[x][0]];else lcol[x]=col[x];
        if(son[x][1])rcol[x]=rcol[son[x][1]];else rcol[x]=col[x];
        t[x]=t[son[x][0]]+t[son[x][1]]+1-(col[x]==rcol[son[x][0]])-(col[x]==lcol[son[x][1]]);
    }
    void change(int x){swap(son[x][0],son[x][1]);swap(lcol[x],rcol[x]);rev[x]^=1;}
    void update(int x,int y){tag[x]=col[x]=lcol[x]=rcol[x]=y;t[x]=1;}
    void down(int x)
    {
        if(rev[x])
        {
            rev[x]=0;
            if(son[x][0])change(son[x][0]);
            if(son[x][1])change(son[x][1]);
        }
        if(tag[x])
        {
            if(son[x][0])update(son[x][0],tag[x]);
            if(son[x][1])update(son[x][1],tag[x]);
            tag[x]=0;
        }
    }
    void rotate(int x)
    {
        int y=fa[x],z=fa[y],k=son[fa[x]][1]==x,w=son[x][k^1];
        if(get(y))son[z][son[z][1]==y]=x;son[x][k^1]=y;son[y][k]=w;
        if(w)fa[w]=y;fa[y]=x;fa[x]=z;
        up(y);up(x);
    }
    void splay(int x)
    {
        int y=x,top=0;st[++top]=y;
        while(get(y))st[++top]=y=fa[y];
        while(top)down(st[top--]);
        while(get(x))
        {
            int y=fa[x],z=fa[y];
            if(get(y))rotate((son[y][0]==x)^(son[z][0]==y)?x:y);rotate(x);
        }up(x);
    }
    void access(int x)
    {
        for(int y=0;x;x=fa[y=x])
        splay(x),son[x][1]=y,up(x);
    }
    void makeroot(int x)
    {
        access(x);splay(x);change(x);
    }
    int findroot(int x)
    {
        access(x);splay(x);
        while(son[x][0])down(x),x=son[x][0];
        splay(x);return x;
    }
    void split(int x,int y)
    {
        makeroot(x);access(y);splay(y);
    }
    void link(int x,int y)
    {
        makeroot(x);if(findroot(y)!=x)fa[x]=y;
    }int n,m,x,y,z;char s[2];
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&x),col[i]=lcol[i]=rcol[i]=x,t[i]=1;
        for(int i=1;i<n;i++)scanf("%d%d",&x,&y),link(x,y);
        while(m--)
        {
            scanf("%s",s+1);
            if(s[1]=='Q')scanf("%d%d",&x,&y),split(x,y),printf("%d
    ",t[y]);
            if(s[1]=='C')scanf("%d%d%d",&x,&y,&z),split(x,y),update(y,z);
        }
        return 0;
    }
    View Code

    P1501 [国家集训队]Tree II

    题解:  注意一下乘法和加法的优先级就行了 

         忘记加siz了导致一直wa 。。。。 其实和线段树是一样的  只是多出了一个点  如果操作保证合法的话 就不用findroot特判了  加速了很多

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
    #define inf 0x3f3f3f3f
    const int N=1e5+10;
    const ll mod=51061;
    int fa[N],son[N][2],rev[N],st[N],siz[N];
    ll sum[N],val[N],mul[N],p[N];
    int get(int x){return son[fa[x]][0]==x||son[fa[x]][1]==x;}
    void up(int x){sum[x]=(sum[son[x][0]]+sum[son[x][1]]+val[x])%mod;siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;}
    void change(int x){swap(son[x][0],son[x][1]);rev[x]^=1;}
    void add(int x,int y){sum[x]=(sum[x]+siz[x]*y)%mod;val[x]=(val[x]+y)%mod;p[x]=(p[x]+y)%mod;}
    void mulit(int x,int y){sum[x]=sum[x]*y%mod;val[x]=val[x]*y%mod;p[x]=p[x]*y%mod;mul[x]=mul[x]*y%mod;}
    void down(int x)
    {
        if(mul[x]!=1)
        {
            if(son[x][0])mulit(son[x][0],mul[x]);
            if(son[x][1])mulit(son[x][1],mul[x]);
            mul[x]=1;
        }
        if(p[x])
        {
            if(son[x][0])add(son[x][0],p[x]);
            if(son[x][1])add(son[x][1],p[x]);
            p[x]=0;
        }
        if(rev[x])
        {
            rev[x]=0;
            if(son[x][0])change(son[x][0]);
            if(son[x][1])change(son[x][1]);
        }
    }
    void rotate(int x)
    {
        int y=fa[x],z=fa[y],k=son[y][1]==x,w=son[x][k^1];
        if(get(y))son[z][son[z][1]==y]=x;son[x][k^1]=y;son[y][k]=w;
        if(w)fa[w]=y;fa[y]=x;fa[x]=z;
        up(y);
    }
    void splay(int x)
    {
        int y=x,top=0;st[++top]=y;
        while(get(y))st[++top]=y=fa[y];
        while(top)down(st[top--]);
        while(get(x))
        {
            int y=fa[x],z=fa[y];
            if(get(y))rotate((son[y][0]==x)^(son[z][0]==y)?x:y);
            rotate(x);
        }up(x);
    }
    void access(int x)
    {
        for(int y=0;x;x=fa[y=x])
        splay(x),son[x][1]=y,up(x);
    }
    void makeroot(int x)
    {
        access(x);splay(x);change(x);
    }
    int findroot(int x)
    {
        access(x);splay(x);
        while(son[x][0])down(x),x=son[x][0];
        splay(x);return x;
    }
    void split(int x,int y)
    {
        makeroot(x);access(y);splay(y);
    }
    void link(int x,int y)
    {
        makeroot(x);fa[x]=y;
    }
    void cut(int x,int y)
    {
        split(x,y);
        fa[x]=son[y][0]=0;
    }int n,m,x,y,z,t,q;char s[20];
    int main()
    {   
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;i++)mul[i]=val[i]=siz[i]=1;
        for(int i=1;i<n;i++)scanf("%d%d",&x,&y),link(x,y);
        while(q--)
        {
            scanf("%s",s+1);
            if(s[1]=='+')scanf("%d%d%d",&x,&y,&z),split(x,y),add(y,z);
            if(s[1]=='-')scanf("%d%d%d%d",&x,&y,&z,&t),cut(x,y),link(z,t);
            if(s[1]=='*')scanf("%d%d%d",&x,&y,&z),split(x,y),mulit(y,z);
            if(s[1]=='/')scanf("%d%d",&x,&y),split(x,y),printf("%lld
    ",sum[y]);
        }
        return 0;
    }
    View Code

    维护生成树:

    P4172 [WC2006]水管局长

    题意: 有n个点 m条边 (保证每时每刻任意两点都联通  且路径可能有多条) 

        操作一: 询问   最小化 x 到y 的某条路径的最大边权 

        操作二: 删除x-y的边  

    题解: 第一眼很像是最小生成树 但是是动态删边的 

        可以考虑时间回溯  就是一开始有一棵最小生成树  不断地加边   显然加入一个边一定会形成环  那么如果新加入的边比这个环的最大边要大 就不用加  反之  删去最大的边然后加入该边肯定是满足正确性的  这样就可以一直维护一个树形结构

        删边和加边很显然是lct 但是之前做的lct都是点权的   可以拆边  对每个边建立一个虚点  每次连两条边即可  除了虚点其他都是没有权值的  反正不影响答案   因为要删除最大值的边  所以splay维护的是编号  而不是权值  否则删边的时候难以找到这个权值对应的是哪个边

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e6;
    int n,m,qq,f[N],vis[N],ans[N];
    int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
    struct Edge{int x,y,v;}edge[N];
    struct Q{int op,x,y,flag;}q[N];
    map<pair<int,int>,int >id;
    ////lct 
    int mx[N],son[N][2],fa[N],rev[N],st[N],val[N];
    int get(int x){return son[fa[x]][0]==x||son[fa[x]][1]==x;}
    void up(int x)
    {
        mx[x]=val[x]; 
        if(edge[mx[son[x][0]]].v>edge[mx[x]].v)mx[x]=mx[son[x][0]];
        if(edge[mx[son[x][1]]].v>edge[mx[x]].v)mx[x]=mx[son[x][1]];
    }
    void change(int x){swap(son[x][0],son[x][1]);rev[x]^=1;}
    void down(int x)
    {
        if(!rev[x])return ;rev[x]=0;
        if(son[x][0])change(son[x][0]);
        if(son[x][1])change(son[x][1]);
    }
    void rotate(int x)
    {
        int y=fa[x],z=fa[y],k=son[fa[x]][1]==x,w=son[x][k^1];
        if(get(y))son[z][son[z][1]==y]=x;son[x][k^1]=y;son[y][k]=w;
        if(w)fa[w]=y;fa[y]=x;fa[x]=z;
        up(y);
    }
    void splay(int x)
    {
        int y=x,top=0;st[++top]=y;
        while(get(y))st[++top]=y=fa[y];
        while(top)down(st[top--]);
        while(get(x))
        {
            int y=fa[x],z=fa[y];
            if(get(y))rotate((son[y][0]==x)^(son[z][0]==y)?x:y);rotate(x);
        }up(x);
    }
    void access(int x)
    {
        for(int y=0;x;x=fa[y=x])
        splay(x),son[x][1]=y,up(x);
    }
    void makeroot(int x)
    {
        access(x);splay(x);change(x);
    }
    void split(int x,int y)
    {
        makeroot(x);access(y);splay(y);
    }
    void link(int x,int y)
    {
        makeroot(x);fa[x]=y;
    }
    void cut(int x,int y)
    {
        split(x,y);fa[x]=son[y][0]=0;
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&qq);int x,y,z;for(int i=1;i<=n;i++)f[i]=i;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            if(x>y)swap(x,y);
            edge[i]=(Edge){x,y,z};
        }
        sort(edge+1,edge+1+m,[](Edge a,Edge b){return a.v<b.v;});
        for(int i=1;i<=m;i++)id[{edge[i].x,edge[i].y}]=i;
        for(int i=1;i<=qq;i++)
        {
            scanf("%d%d%d",&x,&y,&z);if(y>z)swap(y,z);
            q[i]=(Q){x,y,z};
            if(x==2)
            {
                vis[id[{y,z}]]=1;q[i].flag=id[{y,z}];
            }
        }
        for(int i=n+1;i<=n+m;i++)mx[i]=val[i]=i-n;//给每条边预处理一个虚点  等等直接用就行了
        int cnt=0;
        for(int i=1;i<=m;i++)if(!vis[i])//先维护一个最小生成树
        {
            if(find(edge[i].x)==find(edge[i].y))continue;
            f[find(edge[i].x)]=find(edge[i].y);
            link(edge[i].x,i+n);link(edge[i].y,i+n);
            cnt++;
            if(cnt==n-1)break;
        }
        for(int i=qq;i>=1;i--)
        {   
            x=q[i].x;y=q[i].y;
            if(q[i].op==1)
            {
                split(x,y);ans[i]=edge[mx[y]].v;
            }
            else 
            {   
                split(x,y);
                int d=q[i].flag,t=mx[y];
                if(edge[d].v<edge[t].v)
                {
                    cut(edge[t].x,t+n);cut(edge[t].y,t+n);
                    link(x,d+n);link(y,d+n);
                }
            }
        }
        for(int i=1;i<=qq;i++)
        if(q[i].op==1)printf("%d
    ",ans[i]);
        return 0;
    }
    View Code

    P2387 [NOI2014]魔法森林

    题意: 有一个包含n个点m条边的无向图  每条边有a b两个值  要经过这条边  a属性要大于a值 b属性要大于b值 

        问 $min   sum(a+b) $ 使得能从1走到n

    题解:  看起来像两棵最小生成树 其实可以用排序去掉一棵 类似水管局长地维护即可

      

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e6;
    int n,m,qq,f[N],vis[N],ans[N];
    struct Edge{int x,y,a,v;}edge[N];
    
    int maxx[N],son[N][2],fa[N],rev[N],st[N],val[N];
    int get(int x){return son[fa[x]][0]==x||son[fa[x]][1]==x;}
    void up(int x)
    {
        maxx[x]=val[x];
        if(edge[maxx[son[x][0]]].v>edge[maxx[x]].v)maxx[x]=maxx[son[x][0]];
        if(edge[maxx[son[x][1]]].v>edge[maxx[x]].v)maxx[x]=maxx[son[x][1]];
    }
    void change(int x){swap(son[x][0],son[x][1]);rev[x]^=1;}
    void down(int x)
    {
        if(!rev[x])return ;rev[x]=0;
        if(son[x][0])change(son[x][0]);
        if(son[x][1])change(son[x][1]);
    }
    void rotate(int x)
    {
        int y=fa[x],z=fa[y],k=son[fa[x]][1]==x,w=son[x][k^1];
        if(get(y))son[z][son[z][1]==y]=x;son[x][k^1]=y;son[y][k]=w;
        if(w)fa[w]=y;fa[y]=x;fa[x]=z;
        up(y);
    }
    void splay(int x)
    {
        int y=x,top=0;st[++top]=y;
        while(get(y))st[++top]=y=fa[y];
        while(top)down(st[top--]);
        while(get(x))
        {
            int y=fa[x],z=fa[y];
            if(get(y))rotate((son[y][0]==x)^(son[z][0]==y)?x:y);rotate(x);
        }up(x);
    }
    void access(int x)
    {
        for(int y=0;x;x=fa[y=x])
        splay(x),son[x][1]=y,up(x);
    }
    void makeroot(int x)
    {
        access(x);splay(x);change(x);
    }
    void split(int x,int y)
    {
        makeroot(x);access(y);splay(y);
    }
    void link(int x,int y)
    {
        makeroot(x);fa[x]=y;
    }
    int findroot(int x)
    {
        access(x);splay(x);
        while(son[x][0])down(x),x=son[x][0];
        return x;
    }
    void cut(int x,int y)
    {
        split(x,y);fa[x]=son[y][0]=0;
    }
    int a,b,c,d,x,y;
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d%d",&a,&b,&c,&d);
            edge[i]=(Edge){a,b,c,d};
        }
        sort(edge+1,edge+1+m,[](Edge a,Edge b){return a.a<b.a||a.a==b.a&&a.v<b.v;});
        int ans=1e9;
        for(int i=n+1;i<=n+m;i++)val[i]=maxx[i]=i-n;
        for(int i=1;i<=m;i++)
        {   
            x=edge[i].x;y=edge[i].y;a=edge[i].a;b=edge[i].v;
            if(findroot(x)==findroot(y))
            {
                split(x,y);int t=maxx[y];
                if(edge[t].v>b)cut(edge[t].x,t+n),cut(edge[t].y,t+n);
                else continue;
            }
            link(x,i+n),link(y,i+n);
            if(find(1)==find(n))
            {   
                split(1,n);int t=maxx[n];
                ans=min(ans,a+edge[t].v);
            }
        }
        cout<<ans;
        return 0;
    }
    View Code
  • 相关阅读:
    json作为参数传入函数
    js 获取input type="file" 选择的文件大小、文件名称、上次修改时间、类型等信息
    jquery 如何控制滚动条每次向下滚动300px
    [if lt IE 9]
    JS代码判断IE6,IE7,IE8,IE9!
    ios __block typeof 编译错误解决
    ios json结构
    iOS --创建文件夹 ,删除文件夹
    iOS --生产JSON格式,创建JSON文件,创建文件夹,指定储存
    转载 -- iOS开发之JSON格式数据的生成与解析
  • 原文地址:https://www.cnblogs.com/bxd123/p/11626972.html
Copyright © 2011-2022 走看看