1. 程式人生 > 實用技巧 >Luogu1501 [國家集訓隊]Tree II

Luogu1501 [國家集訓隊]Tree II

https://www.luogu.com.cn/problem/P1501

\(LCT\)

注意標記的下放,需要記住一個原則

當該節點被打上標記時,該節點的值需要同時更新

下放標記時直接傳給兒子,這時已經不能更新自己了

採取邊更新邊下放的方式到處都是

#include<cstdio>
#include<algorithm>
#include<iostream>
#define N 100005
#define ls(x) a[x].ch[0]
#define rs(x) a[x].ch[1]
#define fa(x) a[x].f
#define v(x) a[x].val
#define s(x) a[x].sz
#define ans(x) a[x].Sum
#define tag1(x) a[x].tag_add
#define tag2(x) a[x].tag_muti
#define tag(x) a[x].tag_reverse
#define id(x) (ls(fa(x))==x?0:1)
#define ll long long
using namespace std;
char cc;
int x,y,x2,y2,n,m,q[N];
ll c;
ll p=51061;
struct node
{
    int ch[2],f,tag_reverse;
    ll sz,val,Sum,tag_add,tag_muti;
}a[N];
void update(int x)
{
    s(x)=s(ls(x))+s(rs(x))+1;
    ans(x)=(ans(ls(x))+ans(rs(x))+v(x))%p;
}
void push_add(int x,ll y)
{
    v(x)=(v(x)+y)%p;
    ans(x)=(ans(x)+s(x)*y)%p;
    tag1(x)=(tag1(x)+y)%p;
}
void push_mul(int x,ll y)
{
    v(x)=v(x)*y%p;
    ans(x)=ans(x)*y%p;
    tag1(x)=tag1(x)*y%p;
    tag2(x)=tag2(x)*y%p;
}
void push_rev(int x)
{
    tag(x)^=1;
    swap(ls(x),rs(x));
}
void pushdown(int x)
{
    if (tag(x))
    {
        if (ls(x))
            push_rev(ls(x));
        if (rs(x))
            push_rev(rs(x));
        tag(x)=0;
    }
    if (tag2(x)!=1)
    {
        if (ls(x))
            push_mul(ls(x),tag2(x));
        if (rs(x))
            push_mul(rs(x),tag2(x));
        tag2(x)=1;
    }
    if (tag1(x))
    {
        if (ls(x))
            push_add(ls(x),tag1(x));
        if (rs(x))
            push_add(rs(x),tag1(x));
        tag1(x)=0;
    }
}
bool isrt(int x)
{
    return ls(fa(x))!=x && rs(fa(x))!=x;
}
void connect(int x,int F,int son)
{
    fa(x)=F;
    a[F].ch[son]=x;
}
void rot(int x)
{
    int y=fa(x),r=fa(y);
    int yson=id(x),rson=id(y);
    if (isrt(y))
        fa(x)=r; else
        connect(x,r,rson);
    connect(a[x].ch[yson^1],y,yson);
    connect(y,x,yson^1);
    update(y),update(x);
}
void splay(int x)
{
    int g=x,k=0;
    q[++k]=g;
    while (!isrt(g))
        g=fa(g),q[++k]=g;
    while (k)
        pushdown(q[k--]);
    while (!isrt(x))
    {
        int y=fa(x);
        if (isrt(y))
            rot(x); else
        if (id(x)==id(y))
            rot(y),rot(x); else
            rot(x),rot(x);
    }
}
void access(int x)
{
    for (int y=0;x;y=x,x=fa(x))
        splay(x),rs(x)=y,update(x);
}
void makeroot(int x)
{
    access(x);
    splay(x);
    push_rev(x);
}
void split(int x,int y)
{
    makeroot(x);
    access(y);
    splay(y);
}
void link(int x,int y)
{
    makeroot(x);
    access(y);
    splay(y);
    fa(x)=y;
}
void cut(int x,int y)
{
    makeroot(x);
    access(y);
    splay(y);
    fa(x)=ls(y)=0;
    update(y);
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        v(i)=ans(i)=1,s(i)=1,tag1(i)=0,tag2(i)=1;
    for (int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        link(x,y);
    }
    for (int i=1;i<=m;i++)
    {
        cc=getchar();
        while (cc!='+' && cc!='-' && cc!='*' && cc!='/')
            cc=getchar();
        if (cc=='+')
        {
            scanf("%d%d%lld",&x,&y,&c);
            split(x,y);
            push_add(y,c);
        } else
        if (cc=='-')
        {
            scanf("%d%d%d%d",&x,&y,&x2,&y2);
            cut(x,y);
            link(x2,y2);
        } else
        if (cc=='*')
        {
            scanf("%d%d%lld",&x,&y,&c);
            split(x,y);
            push_mul(y,c);
        } else
        {
            scanf("%d%d",&x,&y);
            split(x,y);
            printf("%lld\n",ans(y));
        }
    }
    return 0;
}