【模板】【bzoj2631】tree 动态树

32 篇文章 1 订阅
10 篇文章 0 订阅

Description

 一棵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的余数。

Input

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

Output

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

Sample Input

3 2

1 2

2 3

* 1 3 4

/ 1 1

Sample Output

4

HINT

数据规模和约定

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

Source


同时又加和乘,维护标记和这个题很像:【bzoj1798】[Ahoi2009]Seq 维护序列seq

然后就是LCT的路径操作……

别忘了模,务必不要忘了模!!在maintain函数中务必不要忘了模!!(来自因此浪费了半个下午时间的我)

unsigned int!!不然会WA

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef unsigned int LL;

const int mod = 51061;

const int SZ = 1000010;
const int INF = 1000000010;

struct node{
    node *f,*ch[2];
    LL sz,v,sum;
    LL add,c;
    bool rev;

    void setc(node *x,int d) { (ch[d] = x) -> f = this; }

    void maintain()
    {
        sz = ch[0] -> sz + ch[1] -> sz + 1;
        sum = ((ch[0] -> sum % mod + v % mod) % mod + ch[1] -> sum % mod) % mod;
    }

    void pushdown();

    int dir() { return f -> ch[1] == this; }

    bool isroot() { return f -> ch[0] != this && f -> ch[1] != this; }
}T[SZ], *null, *tree[SZ];

int Tcnt = 0;

node* newnode(int x)
{
    node *k = T + (Tcnt ++);
    k -> ch[0] = k -> ch[1] = k -> f = null;
    k -> sz = 1;
    k -> v = k -> sum = x; 
    k -> add = 0;
    k -> c = 1;
    k -> rev = 0;
    return k;
}

void rotate(node *p)
{
    int d = p -> dir();
    node *fa = p -> f;
    p -> f = fa -> f; 
    if(!fa -> isroot()) p -> f -> ch[fa -> dir()] = p;
    fa -> ch[d] = p -> ch[d ^ 1];
    if(fa -> ch[d] != null) fa -> ch[d] -> f = fa;
    p -> setc(fa,d ^ 1);
    fa -> maintain(); p -> maintain();
}


void pushrev(node *p) { if(p == null) return ; swap(p -> ch[0],p -> ch[1]); p -> rev ^= 1; }

void pushchange(node *p,int c,int add)
{
    p -> v = ((c * p -> v) % mod + add) % mod;
    p -> c = (c * (p -> c % mod)) % mod;
    p -> add = ((c * p -> add) % mod + add) % mod;
    p -> sum = ((c * p -> sum) % mod + (add * p -> sz) % mod) % mod;
}

void node :: pushdown()
{
    if(rev) { pushrev(ch[0]); pushrev(ch[1]); rev ^= 1; }
    if(add || c != 1)
    {
        pushchange(ch[0],c,add);
        pushchange(ch[1],c,add);
        add = 0; c = 1;
    }
}

node *S[SZ];
void pushpath(node *p)
{
    int top = 0;
/*  node *m = p;
    while(!m -> isroot())
    {
        if(m -> ch[0] != null)
        {
            m = m -> ch[0];
        }
        else if(m -> ch[1] != null)
    }*/
    while(!p -> isroot()) S[++ top] = p,p = p -> f;
    S[++ top] = p;
    while(top) S[top --] -> pushdown();
}


void splay(node *p)
{
    pushpath(p);
    while(!p -> isroot())
    {
        if(p -> f -> isroot()) rotate(p);
        else
        {
            if(p -> dir() == p -> f -> dir()) rotate(p -> f),rotate(p);
            else rotate(p),rotate(p);
        }
    }
    p -> maintain();
}

void access(node *p)
{
    node *last = null;
    while(p != null)
    {
        splay(p);
        p -> ch[1] = last; p -> maintain();
        last = p;
        p = p -> f;
    }
}

void toroot(node *p)
{
    access(p);
    splay(p);
    pushrev(p);
}

void link(node *u,node *v)
{
    toroot(u);
    u -> f = v;
}

void cut(node *u,node *v)
{
    toroot(u);
    access(v);
    splay(v);
    v -> ch[0] = u -> f = null;
}

void change(node *u,node *v,LL c,LL add)
{
    toroot(u);
    access(v);
    splay(v);
    pushchange(v,c,add);
}

LL ask_sum(node *u,node *v)
{
    toroot(u);
    access(v);
    splay(v);
    return v -> sum;
}

void init()
{
    null = newnode(0);
    null -> sz = null -> sum = null -> v = 0;
}

void dfs(node *p)
{
    if(p == null) return ;
    printf("%d %d %d\n",p - T,p -> v,p -> sum);
    dfs(p -> ch[0]);
    dfs(p -> ch[1]);
}

int main()
{
//  freopen("2631.in","r",stdin); 
//  freopen("out.txt","w",stdout);  
    init();
    int n,q;
    scanf("%d%d",&n,&q);
    for(int i = 1;i <= n;i ++)
        tree[i] = newnode(1);
    for(int i = 1;i < n;i ++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        link(tree[u],tree[v]);
    }
    while(q --)
    {
        char opt[2];
        scanf("%s",opt);
        if(opt[0] == '+')
        {
            int u,v,add;
            scanf("%d%d%d",&u,&v,&add);
            add %= mod;
            change(tree[u],tree[v],1,add);
        }
        else if(opt[0] == '-')
        {
            int u1,v1,u2,v2;
            scanf("%d%d%d%d",&u1,&v1,&u2,&v2);
            cut(tree[u1],tree[v1]);
            link(tree[u2],tree[v2]);
        }
        else if(opt[0] == '*')
        {
            int u,v,c;
            scanf("%d%d%d",&u,&v,&c);
            c %= mod;
            change(tree[u],tree[v],c,0);
        }
        else
        {
            int u,v;
            scanf("%d%d",&u,&v);
            printf("%u\n",ask_sum(tree[u],tree[v]));
        }
    //  for(int i = 1;i <= n;i ++) dfs(tree[i]), puts("");
    }
    return 0;
}
/*

7 3
2 1
3 1
4 2
5 1
6 5
7 1
+ 5 4 691
* 4 3 4319
/ 4 6
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值