BZOJ2631tree——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行,每行描述一个操作

输出

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

样例输入

3 2
1 2
2 3
* 1 3 4
/ 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

 

LCT,splay每个点维护子树和,单点权值和两个区间修改标记,注意加法和乘法运算顺序即可。开unsigned int即可,开longlong可能会T。

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll unsigned int
using namespace std;
int n,m;
int x,y,z,w;
int mod=51061;
char ch[2];
int f[100010];
int s[100010][2];
int st[100010];
int r[100010];
int size[100010];
ll sum[100010];
ll val[100010];
ll a[100010];
ll b[100010];
int get(int rt)
{
    return rt==s[f[rt]][1];
}
void change(int rt,int x,int y)
{
    if(!rt)
    {
        return ;
    }
    sum[rt]=(sum[rt]*x+y*size[rt])%mod;
    val[rt]=(val[rt]*x+y)%mod;
    a[rt]=(a[rt]*x+y)%mod;
    b[rt]=(b[rt]*x)%mod;
}
void pushup(int rt)
{
    sum[rt]=(sum[s[rt][0]]+sum[s[rt][1]]+val[rt])%mod;
    size[rt]=(size[s[rt][0]]+size[s[rt][1]]+1)%mod;
}
void pushdown(int rt)
{
    if(r[rt])
    {
        swap(s[rt][0],s[rt][1]);
        r[s[rt][0]]^=1;
        r[s[rt][1]]^=1;
        r[rt]^=1;
    }
    int x=a[rt];
    int y=b[rt];
    a[rt]=0;
    b[rt]=1;
    if(x!=0||y!=1)
    {
        change(s[rt][0],y,x);
        change(s[rt][1],y,x);
    }
}
int is_root(int rt)
{
    return s[f[rt]][0]!=rt&&s[f[rt]][1]!=rt;
}
void rotate(int rt)
{
    int fa=f[rt];
    int anc=f[fa];
    int k=get(rt);
    if(!is_root(fa))
    {
        s[anc][fa==s[anc][1]]=rt;
    }
    s[fa][k]=s[rt][k^1];
    f[s[fa][k]]=fa;
    s[rt][k^1]=fa;
    f[fa]=rt;
    f[rt]=anc;
    pushup(fa);
    pushup(rt);
}
void splay(int rt)
{
    int top=0;
    st[++top]=rt;
    for(int i=rt;!is_root(i);i=f[i])
    {
        st[++top]=f[i];
    }
    for(int i=top;i>=1;i--)
    {
        pushdown(st[i]);
    }
    for(int fa;!is_root(rt);rotate(rt))
    {
        if(!is_root(fa=f[rt]))
        {
            rotate(get(rt)==get(fa)?fa:rt);
        }
    }
}
void access(int rt)
{
    for(int x=0;rt;x=rt,rt=f[rt])
    {
        splay(rt);
        s[rt][1]=x;
        pushup(rt);
    }
}
void reverse(int rt)
{
    access(rt);
    splay(rt);
    r[rt]^=1;
}
void split(int x,int y)
{
    reverse(x);
    access(y);
    splay(y);
}
void link(int x,int y)
{
    reverse(x);
    f[x]=y;
}
void cut(int x,int y)
{
    reverse(x);
    access(y);
    splay(y);
    s[y][0]=f[x]=0;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        size[i]=val[i]=sum[i]=b[i]=1;
    }
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        link(x,y);
    }
    while(m--)
    {
        scanf("%s",ch);
        scanf("%d%d",&x,&y);
        if(ch[0]=='+')
        {
            scanf("%d",&z);
            split(x,y);
            change(y,1,z);
        }
        else if(ch[0]=='-')
        {
            scanf("%d%d",&w,&z);
            cut(x,y);
            link(w,z);
        }
        else if(ch[0]=='*')
        {
            scanf("%d",&z);
            split(x,y);
            change(y,z,0);
        }
        else if(ch[0]=='/')
        {
            split(x,y);
            printf("%d\n",sum[y]);
        }
    }
}
posted @ 2018-10-05 13:59  The_Virtuoso  阅读(273)  评论(0编辑  收藏  举报