bzoj2631: tree LCT

LCT基本操作。用long long竟然会被卡常数。。。unsigned int 好。

pushdown递归写果然比较快。。。

维护sum(总和) mul(倍数) add(加的值) val(每个点的值) siz(子树大小)即可。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
#define maxn 100100
#define mod 51061
typedef unsigned int sint;
int tr[maxn][2],fa[maxn],siz[maxn];
sint val[maxn],sum[maxn],mul[maxn],add[maxn];
bool rev[maxn];
int n,m;
inline int getint()
{
    int res=0,f=1;char c;
    while(c=getchar(),c<'0'||c>'9'){if(c=='-')f=-1;}
    res=c-'0';
    while(c=getchar(),c>='0'&&c<='9')res=res*10+c-'0';
    return res*f;
}
inline bool isroot(int k)
{
    return tr[fa[k]][0]!=k && tr[fa[k]][1]!=k;
}
void pushup(int x)
{
    int l=tr[x][0],r=tr[x][1];
    siz[x]=(siz[l]+siz[r]+1)%mod;
    sum[x]=(sum[l]+sum[r]+val[x])%mod;
}
void rever(int x)
{
    rev[x]^=1,swap(tr[x][0],tr[x][1]);
    rev[tr[x][0]]^=1;
    rev[tr[x][1]]^=1;
}
void change(int x,sint y,sint z)
{
    val[x]=(val[x]*y+z)%mod;
    sum[x]=(sum[x]*y+siz[x]*z)%mod;
    mul[x]=(mul[x]*y)%mod;
    add[x]=(add[x]*y+z)%mod;
}
void pushdown(int x)
{
    if(!isroot(x))
        pushdown(fa[x]);
    if(rev[x])
    {
        rever(x);
    }
    if(tr[x][0]) change(tr[x][0],mul[x],add[x]);
    if(tr[x][1]) change(tr[x][1],mul[x],add[x]);
    mul[x]=1,add[x]=0;
}
int sta[maxn],top;
void rotate(int x)
{
    int l,r,y,z;
    y=fa[x];z=fa[y];
    if(tr[y][0]==x) l=0;
    else l=1;r=l^1;
    if(!isroot(y))
    {
        if(tr[z][0]==y) tr[z][0]=x;
        else tr[z][1]=x;
    }
    fa[y]=x;fa[x]=z;fa[tr[x][r]]=y;
    tr[y][l]=tr[x][r];tr[x][r]=y;
    pushup(y);pushup(x);
}
void splay(int x)
{
    pushdown(x);
    int y,z;
    while(!isroot(x))
    {
        y=fa[x];z=fa[y];
        if(!isroot(y))
        {
            if((tr[y][0]==x)^(tr[z][0]==y)) rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
}
void access(int x)
{
    int t=0;
    while(x)
    {
        splay(x);
        tr[x][1]=t;
        pushup(x);
        t=x;x=fa[x];
    }
}
void makeroot(int x)
{
    access(x);splay(x);rev[x]^=1;
}
void link(int x,int y)
{
    makeroot(x);fa[x]=y;splay(x);
}
void cut(int x,int y)
{
    makeroot(x);access(y);splay(y);tr[y][0]=fa[x]=0;
}
int main()
{
    sint a,b,c;
    n=getint();m=getint();
    for(int i=1;i<=n;i++)
    {
        val[i]=1;sum[i]=1;siz[i]=1,mul[i]=1;
    }
    for(int i=1;i<n;i++)
    {
        a=getint();b=getint();
        link(a,b);
    }
    char st[10];
    while(m--)
    {
        scanf("%s",st);
        if(st[0]=='+')
        {
            a=getint();b=getint();c=getint();
            makeroot(a);access(b);splay(b);
            change(b,1,c);
        }
        if(st[0]=='-')
        {
            a=getint();b=getint();
            cut(a,b);
            a=getint();b=getint();
            link(a,b);
        }
        if(st[0]=='*')
        {
            a=getint();b=getint();c=getint();
            makeroot(a);access(b);splay(b);
            change(b,c,0);
        }
        if(st[0]=='/')
        {
            a=getint();b=getint();
            makeroot(a);access(b);splay(b);
            printf("%u\n",sum[b]);
        }
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值