【洛谷P1501】【国家集训队】Tree(LCT)

传送门

就和线段树维护区间加、乘标记一样
板子题

注意虽然模数很小但仍然会爆intint

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int unsigned int
inline int read(){
    char ch=getchar();
    int res=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
    return res*f;
}
const int N=100005;
const int mod=51061;
inline void inc(int &a,int b){
    a=(a+b>=mod)?a+b-mod:a+b;
}
inline void mult(int &a,int b){
    a=(a*b)>=mod?a*b%mod:a*b;
}
namespace Lct{
    int q[N],rev[N],siz[N],add[N],mul[N],val[N],sum[N],son[N][2],fa[N];
    #define lc(u) son[u][0]
    #define rc(u) son[u][1]
    inline bool isrt(int u){
        if(!fa[u])return 1;
        return lc(fa[u])!=u&&rc(fa[u])!=u;
    }
    inline bool isrc(int u){
        return rc(fa[u])==u;
    }
    inline void pushup(int u){
        siz[u]=1,sum[u]=val[u];
        if(lc(u))siz[u]+=siz[lc(u)],inc(sum[u],sum[lc(u)]);
        if(rc(u))siz[u]+=siz[rc(u)],inc(sum[u],sum[rc(u)]);
    }
    inline void pushmul(int u,int k){
        mult(mul[u],k),mult(add[u],k),mult(val[u],k),mult(sum[u],k);
    }
    inline void pushadd(int u,int k){
        inc(add[u],k),inc(val[u],k),inc(sum[u],siz[u]*k%mod);
    }
    inline void pushdown(int u){
        if(rev[u]){
            if(lc(u))rev[lc(u)]^=1;
            if(rc(u))rev[rc(u)]^=1;
            swap(lc(u),rc(u)),rev[u]=0;
        }
        if(mul[u]!=1){
            pushmul(lc(u),mul[u]),pushmul(rc(u),mul[u]),mul[u]=1;
        }
        if(add[u]){
            pushadd(lc(u),add[u]),pushadd(rc(u),add[u]),add[u]=0;
        }
    }
    inline void rotate(int v){
        int u=fa[v],z=fa[u];
        int t=rc(u)==v;
        if(!isrt(u))son[z][rc(z)==u]=v;
        fa[v]=z;
        son[u][t]=son[v][t^1],fa[son[v][t^1]]=u;
        son[v][t^1]=u,fa[u]=v;
        pushup(u),pushup(v);
    }
    inline void splay(int u){
        q[q[0]=1]=u;
        for(int v=u;!isrt(v);v=fa[v])q[++q[0]]=fa[v];
        for(int i=q[0];i;i--)pushdown(q[i]);
        while(!isrt(u)){
            if(!isrt(fa[u])){
                if(isrc(u)==isrc(fa[u]))rotate(fa[u]);
                else rotate(u);
            }
            rotate(u);
        }
        pushup(u);
    }
    inline void access(int u){
        for(int v=0;u;v=u,u=fa[u]){
            splay(u),rc(u)=v;
            if(v)fa[v]=u;
            pushup(u);
        }
    }
    inline int findrt(int u){
        access(u),splay(u);
        while(pushdown(u),lc(u))u=lc(u);
        splay(u);return u;
    }
    inline void makert(int u){
        access(u),splay(u),rev[u]^=1;
    }
    inline void link(int u,int v){
        makert(u),fa[u]=v;
    }
    inline void cut(int u,int v){
        makert(u),access(v),splay(v);
        lc(v)=fa[u]=0,pushup(v);
    }
    inline void split(int u,int v){
        makert(u),access(v),splay(v);
    }
}
using namespace Lct;
char op[5];
int n,m;
signed main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)mul[i]=val[i]=1;
    for(int i=1;i<n;i++){
        int u=read(),v=read();
        link(u,v);
    }
    while(m--){
        scanf("%s",op);
        switch(op[0]){
            case '+':{
                int u=read(),v=read(),k=read();
                split(u,v),pushadd(v,k);
                break;
            }
            case '-':{
                int u=read(),v=read();
                cut(u,v),u=read(),v=read();
                link(u,v);
                break;
            }
            case '/':{
                int u=read(),v=read();
                split(u,v),cout<<sum[v]<<'\n';
                break;
            }
            default:{
                int u=read(),v=read(),k=read();
                split(u,v),pushmul(v,k);
                break;
            }
        }
    }
}
posted @ 2019-03-20 14:22  Stargazer_cykoi  阅读(136)  评论(0编辑  收藏  举报