[省选前题目整理][清橙A1303]tree(LCT)

题目链接

http://www.tsinsen.com/A1303

思路

非常好的LCT模板题。。。
乘法和加法lazy tag是可以叠加的,这个做法和线段树的lazy tag叠加是完全一样的。。。
刚开始pushdown标记很傻叉地写拙了,害得我盲调了半个多小时。。。郁闷。。。

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXN 200000
#define MOD 51061
#define lson ch[o][0]
#define rson ch[o][1]

using namespace std;

typedef unsigned int uint;

int ch[MAXN][2],fa[MAXN],size[MAXN];
uint sum[MAXN],multag[MAXN],addtag[MAXN],val[MAXN];
int stack[MAXN],top=0;
bool rev[MAXN];

bool isRoot(int o)
{
    return ch[fa[o]][0]!=o&&ch[fa[o]][1]!=o;
}

void pushup(int o)
{
    sum[o]=(val[o]+sum[lson]+sum[rson])%MOD;
    size[o]=(size[lson]+size[rson]+1)%MOD;
}

void cal(int o,uint mulv,uint addv) //子树o对应区间先乘上mulv后加上addv
{
    if(!o) return;
    val[o]=((val[o]*mulv)%MOD+addv)%MOD;
    sum[o]=((sum[o]*mulv)%MOD+addv*size[o]%MOD)%MOD;
    addtag[o]=(addtag[o]*mulv+addv)%MOD; //!!!!!!
    multag[o]=(multag[o]*mulv)%MOD;
}

void pushdown(int o)
{
    if(rev[o])
    {
        rev[lson]^=1;
        rev[rson]^=1;
        swap(lson,rson);
        rev[o]=false;
    }
    if(multag[o]!=1||addtag[o]!=0) cal(lson,multag[o],addtag[o]),cal(rson,multag[o],addtag[o]); //!!!!!!!!!!
    multag[o]=1,addtag[o]=0;
}

void rot(int x)
{
    int y=fa[x],z=fa[y];
    int p,q;
    if(ch[y][0]==x) p=0;
    else p=1;
    q=p^1;
    if(!isRoot(y))
    {
        if(ch[z][0]==y) ch[z][0]=x;
        else ch[z][1]=x;
    }
    fa[x]=z,fa[y]=x;
    ch[y][p]=ch[x][q];
    fa[ch[x][q]]=y;
    ch[x][q]=y;
    pushup(y);
    pushup(x);
}

void splay(int x)
{
    top=0;
    stack[++top]=x;
    for(int i=x;!isRoot(i);i=fa[i]) stack[++top]=fa[i];
    for(int i=top;i>=1;i--) pushdown(stack[i]);
    while(!isRoot(x))
    {
        int y=fa[x],z=fa[y];
        if(!isRoot(y))
        {
            if((ch[y][0]==x)==(ch[z][0]==y)) rot(y);
            else rot(x);
        }
        rot(x);
    }
}

void access(int x) //打通x到根节点的关键路径
{
    int tmp=0;
    while(x)
    {
        splay(x);
        ch[x][1]=tmp;
        pushup(x); //!!!!!!
        tmp=x;
        x=fa[x];
    }
}

void makeroot(int x) //使x成为根节点
{
    access(x);
    splay(x);
    rev[x]^=1;
}

void link(int x,int y) //连接x,y,y是x的父亲
{
    makeroot(x);
    fa[x]=y;
}

void cut(int x,int y) //断开x,y,y是x父亲
{
    makeroot(x);
    access(y);
    splay(y);
    ch[y][0]=fa[x]=0;
}

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        link(u,v);
    }
    for(int i=1;i<=n;i++)
        val[i]=sum[i]=multag[i]=size[i]=1;
    for(int i=1;i<=m;i++)
    {
        char cmd[10];
        int x,y,addv,mulv;
        scanf("%s%d%d",cmd,&x,&y);
        if(cmd[0]=='+') //x到y路径加
        {
            scanf("%d",&addv);
            makeroot(x);
            access(y);
            splay(y);
            cal(y,1,addv);
        }
        else if(cmd[0]=='-') //cut and link
        {
            cut(x,y);
            scanf("%d%d",&x,&y);
            link(x,y);
        }
        else if(cmd[0]=='*') //路径乘法
        {
            scanf("%d",&mulv);
            makeroot(x);
            access(y);
            splay(y);
            cal(y,mulv,0);
        }
        else if(cmd[0]=='/') //路径和
        {
            makeroot(x);
            access(y);
            splay(y);
            printf("%d\n",sum[y]);
        }
    }
    return 0;
}

你可能感兴趣的:([省选前题目整理][清橙A1303]tree(LCT))