BZOJ 2631 tree | Luogu P1501 [国家集训队]Tree II (LCT 多重标记下放)

链接:https://www.luogu.org/problemnew/show/P1501

题面:

题目描述

一棵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 (伍一鸣)

 

思路:

写法跟线段树差不多,修改i下pushdown多维护连个标记就好了。

实现代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ls c[x][0]
#define rs c[x][1]
const int M = 4e5+10;
const int inf = 1e9;
const int mod = 51061;
int top;
int sum[M],c[M][2],val[M],fa[M],rev[M],mn[M],S[M],tmp[M];
int siz[M],mul[M],add[M];
inline void up(int x){
    //cout<<sum[x]<<" "<<sum[ls]<<" "<<sum[rs]<<" "<<val[x]<<endl;
    sum[x] = (sum[ls] + sum[rs] + val[x])%mod;
    siz[x] = (siz[ls] + siz[rs] + 1)%mod;;
}

inline void pushrev(int x){
    swap(ls,rs); rev[x] ^= 1;
}

inline void pushmul(int x,int c){
    mul[x] = (1LL*mul[x]*c)%mod;
    add[x] = (1LL*add[x]*c)%mod;
    sum[x] = (1LL*sum[x]*c)%mod;
    val[x] = (1LL*val[x]*c)%mod;
    //cout<<mul[x]<<" "<<val[x]<<endl;
}

inline void pushadd(int x,int c){
    add[x] = (add[x] + c)%mod;
    val[x] = (val[x] + c)%mod;
    sum[x] = (1LL*sum[x]+1LL*siz[x]*c)%mod;
}

inline bool isroot(int x){
    return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
}

inline void rotate(int x){
    int y = fa[x],z = fa[y];
    int k = c[y][1] == x;
    if(!isroot(y)) c[z][c[z][1]==y]=x;
    fa[x] = z;
    c[y][k] = c[x][k^1]; fa[c[x][k^1]] = y;
    c[x][k^1] = y; fa[y] = x;
    up(y); up(x);
}

inline void pushdown(int x){
    if(rev[x]){
        if(ls) pushrev(ls);
        if(rs) pushrev(rs);
        rev[x] = 0;
    }
    if(mul[x]!=1){
        if(ls) pushmul(ls,mul[x]);
        if(rs) pushmul(rs,mul[x]);
        mul[x] = 1;
    }
    if(add[x]){
        if(ls) pushadd(ls,add[x]);
        if(rs) pushadd(rs,add[x]);
        add[x] = 0;
    }
}

inline void splay(int x){
    S[top=1]=x;
    for(int i = x;!isroot(i);i=fa[i]) S[++top] = fa[i];
    while(top) pushdown(S[top--]);
    while(!isroot(x)){
        int y = fa[x],z = fa[y];
        if(!isroot(y))
            (c[y][1]==x)^(c[z][1]==y)?rotate(x):rotate(y);
        rotate(x);
    }
}

inline void access(int x){
    for(int y = 0;x;y = x,x = fa[x])
        splay(x),c[x][1] = y,up(x);
}

inline void makeroot(int x){
    access(x); splay(x); pushrev(x);
}

inline void split(int x,int y){
    makeroot(x); access(y); splay(y);
}

inline void link(int x,int y){
    makeroot(x);fa[x] = y;
}

inline void cut(int x,int y){
    split(x,y); fa[x] = c[y][0] = 0; up(y);
}

inline int findroot(int x){
    access(x); splay(x);
    while(ls) x = ls;
    return x;
}

int main()
{
    int n,q,u,v,x,y,k;
    scanf("%d%d",&n,&q);
    for(int i = 1;i <= n;i ++) val[i] = mul[i] = 1;
    for(int i = 1;i < n;i ++){
        scanf("%d%d",&u,&v);
        link(u,v);
    }
    char op[10];
    while(q--){
        scanf("%s",op);
        scanf("%d%d",&u,&v);
        if(op[0] == '+') {
            scanf("%d",&k);
            split(u,v); pushadd(v,k);
        }
        else if(op[0] == '-'){
            scanf("%d%d",&x,&y);
            cut(u,v); link(x,y);
        }
        else if(op[0] == '*'){
            scanf("%d",&k);
            split(u,v); pushmul(v,k);
        }
        else if(op[0] == '/'){
            //cout<<u<<" "<<v<<endl;
            split(u,v); printf("%d\n",sum[v]);
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/kls123/p/10796586.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值