• [洛谷P1501] [国家集训队]Tree II(LCT模板)


    传送门

    这是一道LCT的板子题,说白了就是在LCT上支持线段树2的操作。

    所以我只是来存一个板子,并不会讲什么(再说我也不会,只能误人子弟2333)。

    不过代码里的注释可以参考一下。

    Code

    #include<bits/stdc++.h>
    using namespace std;
    typedef unsigned int uint;
    const int N=1e5+5;
    const uint mod=51061;
    inline int read(){
        int x=0,w=0;char ch=0;
        while(!isdigit(ch)) w|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        return w?-x:x;
    }
    int f[N],sz[N],c[N][2];
    uint v[N],s[N],ml[N],ad[N];//int是会爆的 
    bool rv[N];
    #define lc c[x][0]
    #define rc c[x][1]
    #define mul(x) x*=val,x%=mod 
    #define add(x) x+=val,x%=mod 
    //我习惯的写法是判断 not root 
    inline bool nrt(int x){return c[f[x]][0]==x||c[f[x]][1]==x;};
    void pushup(int x){
        s[x]=(s[lc]+s[rc]+v[x])%mod;
        sz[x]=sz[lc]+sz[rc]+1; 
    }
    //自定义的优先级:乘法>加法>翻转 
    void Rev(int x){lc^=rc^=lc^=rc;rv[x]^=1;};
    void Mul(int x,uint val){mul(v[x]),mul(s[x]),mul(ml[x]),mul(ad[x]);}
    void Add(int x,uint val){add(v[x]);add(ad[x]);val*=sz[x];val%=mod;add(s[x]);}
    void pushdown(int x){
        if(ml[x]^1) Mul(lc,ml[x]),Mul(rc,ml[x]),ml[x]=1;
        if(ad[x]) Add(lc,ad[x]),Add(rc,ad[x]),ad[x]=0; 
        if(rv[x]) Rev(lc),Rev(rc),rv[x]=0;
    }
    //以下跟普通的LCT没两样 
    int get(int x){return x==c[f[x]][1];}
    void link(int x,int y,int d){c[x][d]=y;f[y]=x;}
    void rotate(int x){
        int y=f[x],z=f[y],d=get(x);
        if(nrt(y)) c[z][get(y)]=x;f[x]=z;
        //如果y=rt,说明y->z是一条虚边,也就是说x和z分属两棵不同的Splay,如果这样还连边z->x的话,后果emmm…… 
        //但x->z必须连,因为就算y是根,把x旋上去后x就成根了,而LCT中一棵Spaly的根的父边一定是一条虚边(原树的根所属的Splay除外),相当于x继承了y连虚边的使命。。。 
        link(y,c[x][d^1],d);
        link(x,y,d^1);
        pushup(y),pushup(x);
    }
    int st[N],tp;
    void splay(int x){
        int t=x;
        //手动用栈来pushdown 
        st[tp=1]=t;
        while(nrt(t)) st[++tp]=t=f[t];
        while(tp) pushdown(st[tp--]);
        for(;nrt(x);rotate(x)){
            int y=f[x];
            if(nrt(y)) get(x)^get(y)?rotate(x):rotate(y);
        }   
    }
    void access(int x){
        for(int y=0;x;x=f[y=x])
            splay(x),c[x][1]=y,pushup(x);
    }
    void makert(int x){
        access(x),splay(x),Rev(x);
    }
    int findrt(int x){
        access(x),splay(x);
        while(lc) pushdown(x),x=lc;
        splay(x);return x;
    }
    void split(int x,int y){
        makert(x),access(y),splay(y);
    }
    void link(int x,int y){
        makert(x);if(findrt(y)^x) f[x]=y;
    }
    void cut(int x,int y){
        makert(x);
        //在这道题中由于保证了cut操作合法因此应该可以不加判断 
        if(findrt(y)==x&&f[y]==x&&!c[y][0]) f[y]=c[x][1]=0,pushup(x);
    }
    int n,m;
    int main(){
        n=read(),m=read();
        for(int i=1;i<=n;++i) v[i]=ml[i]=sz[i]=1; 
        for(int i=1;i<n;++i) link(read(),read()); 
        char op[2];int x,y;
        while(m--){
            scanf("%s",op); 
            x=read(),y=read();
            switch(op[0]){
                case '+':split(x,y);Add(y,read());break;
                case '-':cut(x,y);link(read(),read());break;
                case '*':split(x,y);Mul(y,read());break;
                case '/':split(x,y);cout<<s[y]<<endl;break; 
            }
        }
        return 0;
    }
    LCT模板
  • 相关阅读:
    u-boot.lds分析
    u-boot的makefile中的一些目录的设定,以及涉及的shell,make语法。
    u-boot入门第一步,分析mkconfig
    uboot学习——Makefile里的echo使用!
    Linux下的打包与压缩和tar命令!
    关于undefined reference的问题
    JZ2440 编译Uboot1.1.6 undefined reference to ‘raise’
    POJ 1094 Sorting It All Out
    链式前向星
    Codeforces Round #197 (Div. 2) A~D
  • 原文地址:https://www.cnblogs.com/gosick/p/11256578.html
Copyright © 2020-2023  润新知