洛谷P1501 [国家集训队]Tree II(打标记lct)

题目描述

一棵n个点的树,每个点的初始权值为1。对于这棵树有q个操作,每个操作为以下四种操作之一:

  • + u v c:将u到v的路径上的点的权值都加上自然数c;

  • - u1 v1 u2 v2:将树中原有的边(u1,v1)删除,加入一条新边(u2,v2),保证操作完之后仍然是一棵树;

  • * u v c:将u到v的路径上的点的权值都乘上自然数c;

  • / u v:询问u到v的路径上的点的权值和,求出答案对于51061的余数。

输入输出格式

输入格式:

 

第一行两个整数n,q

接下来n-1行每行两个正整数u,v,描述这棵树

接下来q行,每行描述一个操作

 

输出格式:

 

对于每个/对应的答案输出一行

 

输入输出样例

输入样例#1: 复制
3 2
1 2
2 3
* 1 3 4
/ 1 1
输出样例#1: 复制
4

说明

10%的数据保证,1<=n,q<=2000

另外15%的数据保证,1<=n,q<=5*10^4,没有-操作,并且初始树为一条链

另外35%的数据保证,1<=n,q<=5*10^4,没有-操作

100%的数据保证,1<=n,q<=10^5,0<=c<=10^4

By (伍一鸣)

题解:这题其实没有什么很难的地方,主要考点就是lct的打标记(还是两个orz),显然链修改跟线段树的打标记是一样的

就是酱紫了~

结果%=写成%调了一个晚上2333

代码如下

#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 100010
#define mod 51061
#define lson ch[x][0]
#define rson ch[x][1]
#define int long long
using namespace std;

int tag1[N],tag2[N],tag3[N],sum[N],sz[N],f[N],ch[N][2],w[N];

int not_root(int now)
{
    int x=f[now];
    return lson==now||rson==now;
}

int push_up(int x)
{
    sum[x]=(sum[lson]+sum[rson]+w[x])%mod;
    sz[x]=sz[lson]+sz[rson]+1;
}

int rev(int x)
{
    swap(lson,rson);
    tag1[x]^=1;
}

int add(int x,int cost)
{
    sum[x]+=cost*sz[x];
    sum[x]%=mod;
    w[x]+=cost;
    w[x]%=mod;
    tag2[x]+=cost;
    tag2[x]%=mod;
}

int mul(int x,int cost)
{
    sum[x]*=cost;
    sum[x]%=mod;
    w[x]*=cost;
    w[x]%=mod;
    tag3[x]*=cost;
    tag3[x]%=mod;
    tag2[x]*=cost;
    tag2[x]%=mod;
}

int push_down(int x)
{
    if(tag3[x]!=1)
    {
        mul(lson,tag3[x]);
        mul(rson,tag3[x]);
        tag3[x]=1;
    }
    if(tag2[x])
    {
        add(lson,tag2[x]);
        add(rson,tag2[x]);
        tag2[x]=0;
    }
    if(tag1[x])
    {
        rev(lson);
        rev(rson);
        tag1[x]=0;
    }
}

int rotate(int x)
{
    int y=f[x],z=f[y],kd=ch[y][1]==x,xs=ch[x][!kd];
    if(not_root(y))
    {
        ch[z][ch[z][1]==y]=x;
    }
    ch[x][!kd]=y;
    ch[y][kd]=xs;
    if(xs) f[xs]=y;
    f[y]=x;
    f[x]=z;
    push_up(y);
}

int push_all(int x)
{
    if(not_root(x))
    {
        push_all(f[x]);
    }
    push_down(x);
}

int splay(int x)
{
    int y,z;
    push_all(x);
    while(not_root(x))
    {
        y=f[x],z=f[y];
        if(not_root(y))
        {
            (ch[y][0]==x)^(ch[z][0]==y)?rotate(x):rotate(y);
        }
        rotate(x);
    }
    push_up(x);
}

int access(int x)
{
    for(int y=0; x; y=x,x=f[x])
    {
        splay(x);
        rson=y;
        push_up(x);
    }
}

int make_root(int x)
{
    access(x);
    splay(x);
    rev(x);
}

int split(int x,int y)
{
    make_root(x);
    access(y);
    splay(y);
}

int link(int x,int y)
{
    make_root(x);
    f[x]=y;
}

int cut(int x,int y)
{
    split(x,y);
    f[x]=ch[y][0]=0;
}

char s[3];
int n,m;

signed main()
{
    scanf("%lld %lld",&n,&m);
    for(int i=1; i<=n; i++)
    {
        sum[i]=w[i]=tag3[i]=sz[i]=1;
    }
    for(int i=1; i<n; i++)
    {
        int from,to;
        scanf("%lld %lld",&from,&to);
        link(from,to);
    }
    for(int i=1; i<=m; i++)
    {
        scanf("%s",s);
        if(s[0]=='*')
        {
            int x,y,cost;
            scanf("%lld %lld %lld",&x,&y,&cost);
            split(y,x);
            mul(x,cost);
        }
        if(s[0]=='-')
        {
            int u1,v1,u2,v2;
            scanf("%lld %lld %lld %lld",&u1,&v1,&u2,&v2);
            cut(u1,v1);
            link(u2,v2);
        }
        if(s[0]=='+')
        {
            int x,y,cost;
            scanf("%lld %lld %lld",&x,&y,&cost);
            split(y,x);
            add(x,cost);
        }
        if(s[0]=='/')
        {
            int u,v;
            scanf("%lld %lld",&u,&v);
            split(u,v);
            printf("%lld
",sum[v]);
        }
    }
}
原文地址:https://www.cnblogs.com/stxy-ferryman/p/9477499.html