BZOJ2631: tree

裸的lct…注意*和+标记之间的影响以及下放顺序即可
省选前练习模板系列…
讲道理开unsigned int就可以了,常数会小一些,不过我的能过就无所谓了…

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
//by:MirrorGray
using namespace std;
const int N=211111,mod=51061;
struct LCT{int l,r,fa,d,sum,rev,add,mul,size;}sp[N];

int MOD(int x){
    while(x>=mod)x-=mod;
    while(x<0)x+=mod;
    return x;
}

void rev(int tr){
    if(!tr)return ;
    swap(sp[tr].l,sp[tr].r);
    sp[tr].rev^=1;
}

void add(int tr,int d){
    if(!tr||!d)return ;
    sp[tr].d=MOD(sp[tr].d+d);
    sp[tr].sum=MOD(sp[tr].sum+(ll)sp[tr].size*d%mod);
    sp[tr].add=MOD(sp[tr].add+d);
}

void mul(int tr,int d){
    if(!tr||d==1)return ;
    sp[tr].d=(ll)sp[tr].d*d%mod;
    sp[tr].sum=(ll)sp[tr].sum*d%mod;
    sp[tr].add=(ll)sp[tr].add*d%mod;
    sp[tr].mul=(ll)sp[tr].mul*d%mod;
}

void down(int tr){
    int l=sp[tr].l,r=sp[tr].r;
    if(sp[tr].rev)rev(l),rev(r),sp[tr].rev=0;
    if(sp[tr].mul!=1){
        mul(l,sp[tr].mul);
        mul(r,sp[tr].mul);
        sp[tr].mul=1;
    }
    if(sp[tr].add){
        add(l,sp[tr].add);
        add(r,sp[tr].add);
        sp[tr].add=0;
    }
}

void up(int tr){
    int l=sp[tr].l,r=sp[tr].r;
    sp[tr].size=1;sp[tr].sum=sp[tr].d;
    if(l){
        sp[tr].size+=sp[l].size;
        sp[tr].sum=MOD(sp[tr].sum+sp[l].sum);
    }
    if(r){
        sp[tr].size+=sp[r].size;
        sp[tr].sum=MOD(sp[tr].sum+sp[r].sum);
    }
}

bool is(int tr){
    return sp[sp[tr].fa].l!=tr&&sp[sp[tr].fa].r!=tr;
}

void zig(int tr){
    int y=sp[tr].fa;
    sp[y].l=sp[tr].r;
    if(sp[tr].r)sp[sp[tr].r].fa=y;
    sp[tr].fa=sp[y].fa;
    if(sp[y].fa){
        if(sp[sp[y].fa].l==y)sp[sp[y].fa].l=tr;
        else if(sp[sp[y].fa].r==y)sp[sp[y].fa].r=tr;
    }
    sp[tr].r=y;sp[y].fa=tr;
    up(y);
}

void zag(int tr){
    int y=sp[tr].fa;
    sp[y].r=sp[tr].l;
    if(sp[tr].l)sp[sp[tr].l].fa=y;
    sp[tr].fa=sp[y].fa;
    if(sp[y].fa){
        if(sp[sp[y].fa].l==y)sp[sp[y].fa].l=tr;
        else if(sp[sp[y].fa].r==y)sp[sp[y].fa].r=tr;
    }
    sp[tr].l=y;sp[y].fa=tr;
    up(y);
}

int list[N];
void splay(int tr){
    int p=tr,t=0;
    while(!is(p))list[++t]=p,p=sp[p].fa;
    if(p)down(p);
    for(int i=t;i;i--)down(list[i]);
    while(!is(tr)){
        int y=sp[tr].fa;
        if(is(y)){
            if(sp[y].l==tr)zig(tr);
            else zag(tr);
        }
        else{
            if(sp[sp[y].fa].l==y){
                if(sp[y].l==tr)zig(y),zig(tr);
                else zag(tr),zig(tr);
            }
            else{
                if(sp[y].l==tr)zig(tr),zag(tr);
                else zag(y),zag(tr);
            }
        }
    }
    up(tr);
}

void access(int tr){
    int y=0;
    while(tr){
        splay(tr);sp[tr].r=y;
        up(tr);
        y=tr;tr=sp[tr].fa;
    }
}

void movert(int tr){
    access(tr);splay(tr);rev(tr);
}

void link(int a,int b){
    movert(b);sp[b].fa=a;
}

void cut(int a,int b){
    movert(a);access(b),splay(b);
    if(sp[b].l!=a)while(true)puts("fuck");
    sp[b].l=0;sp[a].fa=0;
    up(b);
}

int main(){
    int n,q;scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)sp[i].d=sp[i].mul=1,up(i);
    for(int i=1;i<n;i++){
        int a,b;scanf("%d%d",&a,&b);
        link(a,b);
    }
    while(q--){
        char s[2];scanf("%s",s);
        if(s[0]=='+'){
            int a,b,c;scanf("%d%d%d",&a,&b,&c);
            movert(a);access(b);splay(b);add(b,c);
        }
        if(s[0]=='-'){
            int a,b,c,d;scanf("%d%d%d%d",&a,&b,&c,&d);
            cut(a,b);link(c,d);
        }
        if(s[0]=='*'){
            int a,b,c;scanf("%d%d%d",&a,&b,&c);
            movert(a);access(b);splay(b);mul(b,c);
        }
        if(s[0]=='/'){
            int a,b;scanf("%d%d",&a,&b);
            movert(a);access(b);splay(b);
            printf("%d\n",sp[b].sum);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值