BZOJ2631:tree(LCT)

传送门

题意:
支持一颗动态树,可以路径乘,加。

题解:LCT

乘一个点只需要把addtag乘,pushdown的时候先pushdown乘的标记就行了。

#include<bits/stdc++.h>
using namespace std;
typedef unsigned int uint;
struct IO{
    streambuf *ib,*ob;
    inline void init(){
        ios::sync_with_stdio(false);
        cin.tie(NULL);cout.tie(NULL);
        ib=cin.rdbuf();ob=cout.rdbuf();
    }
    inline int read(){
        static char ch;static int i,f;
        ch=ib->sbumpc();i=0,f=1;
        while(!isdigit(ch)){
            if(ch==-1)return false;
            if(ch=='-')f=-1;
            ch=ib->sbumpc();
        }
        while(isdigit(ch)){
            i=(i+(i<<2)<<1)+ch-'0';
            ch=ib->sbumpc();
        }
        return ((f>0)?i:-i);
    }
    inline void W(int x){
        static int buf[50];
        if(!x){ob->sputc('0');return;}
        if(x<0){ob->sputc('-');x=-x;}
        while(x){buf[++buf[0]]=x%10;x/=10;}
        while(buf[0]){ob->sputc(buf[buf[0]--]+'0');}
    }
}io;
const int Maxn=1e5+50,INF=0x3f3f3f3f;
uint n,m,mod=51061;
struct node
{
    node *fa,*lc,*rc;
    uint sze,sum,val,revtag,multag,addtag;
    node():fa(NULL),lc(NULL),rc(NULL),sze(1){}
    inline void upt(){
        sze=(lc?lc->sze:0)+(rc?rc->sze:0)+1;
        sum=((lc?lc->sum:0)+(rc?rc->sum:0)+val)%mod;
    }
    inline void rev(){
        swap(lc,rc);revtag^=1;
    }
    inline void add(uint v){
        sum=(sum+sze*v)%mod;
        val=(val+v)%mod;
        addtag=(addtag+v)%mod;
    }
    inline void mul(uint v){ 
        addtag=addtag*v%mod;
        sum=sum*v%mod;
        val=val*v%mod;
        multag=multag*v%mod;
    }
    inline void pushdown(){
        if(revtag){
            if(lc)lc->rev();
            if(rc)rc->rev();
            revtag=0;
        }
        if(multag!=1){
            if(lc)lc->mul(multag);
            if(rc)rc->mul(multag);
            multag=1;
        }
        if(addtag){
            if(lc)lc->add(addtag);
            if(rc)rc->add(addtag);
            addtag=0;
        }
    }
};

struct LCT{
    node Pool[Maxn],*pool,*des,*tr[Maxn];
    LCT(){pool=Pool;}
    inline bool isroot(node *x){
        return (!x->fa)||(x->fa->lc!=x&&x->fa->rc!=x);
    }
    inline bool which(node *x){
        return x->fa->lc==x;
    }
    inline void rotate(node *x){
        node *y=x->fa,*z=y->fa;
        if(!isroot(y))(z->lc==y?z->lc:z->rc)=x;
        x->fa=z;y->fa=x;
        if(y->lc==x){
            node *b=x->rc;
            x->rc=y;y->lc=b;
            if(b)b->fa=y;
        }
        else{
            node *b=x->lc;
            x->lc=y;y->rc=b;
            if(b)b->fa=y;
        }
        y->upt();x->upt();
    }
    inline void splay(node *x){
        static node *que[Maxn];static int tail=0;
        que[tail=1]=x;
        for(node *y=x;!isroot(y);y=y->fa)que[++tail]=y->fa;
        for(int i=tail;i>=1;i--)que[i]->pushdown();
        while(!isroot(x)){
            node *y=x->fa;
            if(!isroot(y))(which(y)^which(x))?(rotate(x)):(rotate(y));
            rotate(x);
        }
    }
    inline void access(node *x){
        for(node *y=NULL;x;y=x,x=x->fa){
            splay(x);x->rc=y;
            if(y)y->fa=x;
            x->upt();
        }
    }
    inline void makeroot(node *x){
        access(x);splay(x);x->rev();
    }
    inline void link(node *x,node *fa){
        makeroot(x);x->fa=fa;
    }
    inline void cut(node *x,node *fa){
        makeroot(fa);access(x);splay(x);
        x->lc->fa=NULL;x->lc=NULL;x->upt();
    }
    inline void addval(node *x,node *y,uint val){
        makeroot(x);access(y);splay(y);
        y->add(val);
    }
    inline void mulval(node *x,node *y,uint val){
        makeroot(x);access(y);splay(y);
        y->mul(val);
    }
    inline void query(node *x,node *y){
        makeroot(x);access(y);splay(y);
        io.W(y->sum);io.ob->sputc('\n');
    }
}lct;


int main(){
    io.init();n=io.read();m=io.read();
    for(int i=1;i<=n;i++)lct.tr[i]=++lct.pool,lct.tr[i]->multag=1;
    for(int i=1;i<n;i++){
        int x=io.read(),y=io.read();
        lct.link(lct.tr[x],lct.tr[y]);
    }
    for(int i=1;i<=n;i++){
        lct.addval(lct.tr[i],lct.tr[i],1);
    }
    for(int i=1;i<=m;i++){
        static char ch[8];
        cin>>(ch+1);int x=io.read(),y=io.read();
        if(ch[1]=='*'){
            int c=io.read()%mod;
            lct.mulval(lct.tr[x],lct.tr[y],c);
        }
        else if(ch[1]=='+'){
            int c=io.read()%mod;
            lct.addval(lct.tr[x],lct.tr[y],c);
        }
        else if(ch[1]=='/'){
            lct.query(lct.tr[x],lct.tr[y]);
        }
        else{
            lct.cut(lct.tr[x],lct.tr[y]);
            x=io.read();y=io.read();
            lct.link(lct.tr[x],lct.tr[y]);
        }
    }
}  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值