BZOJ_2631_tree_LCT

BZOJ_2631_tree_LCT

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


 LCT模板题。注意乘法和加法下传的顺序。

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 100050
#define mod 51061
#define ls ch[p][0]
#define rs ch[p][1]
#define get(x) (ch[f[x]][1]==x)
typedef unsigned int ui;
int n,m,ch[N][2],f[N],rev[N];
ui sum[N],mul[N],add[N],siz[N],val[N];
char opt[10];
inline bool isrt(int x) {
    return ch[f[x]][0]!=x&&ch[f[x]][1]!=x;
}
void pushdown(int p) {
    if(mul[p]!=1) {
        ui u=mul[p];
        sum[ls]=sum[ls]*u%mod; mul[ls]=mul[ls]*u%mod; add[ls]=add[ls]*u%mod; val[ls]=val[ls]*u%mod;
        sum[rs]=sum[rs]*u%mod; mul[rs]=mul[rs]*u%mod; add[rs]=add[rs]*u%mod; val[rs]=val[rs]*u%mod;
        mul[p]=1;
    }
    if(add[p]) {
        ui d=add[p];
        sum[ls]=(sum[ls]+siz[ls]*d%mod)%mod; add[ls]=(add[ls]+d)%mod; val[ls]=(val[ls]+d)%mod;
        sum[rs]=(sum[rs]+siz[rs]*d%mod)%mod; add[rs]=(add[rs]+d)%mod; val[rs]=(val[rs]+d)%mod;
        add[p]=0;
    }
    if(rev[p]) {
        swap(ch[ls][0],ch[ls][1]);
        swap(ch[rs][0],ch[rs][1]);
        rev[ls]^=1; rev[rs]^=1;
        rev[p]=0;
    }
    /*cal(ls , add[p] , mul[p] , rev[p]);
    cal(rs , add[p] , mul[p] , rev[p]);
    add[p] = rev[p] = 0 , mul[p] = 1;*/
}
void pushup(int p) {
    siz[p]=siz[ls]+siz[rs]+1;
    sum[p]=(sum[ls]+sum[rs]+val[p])%mod;
}
void update(int p) {
    if(!isrt(p)) update(f[p]);
    pushdown(p);
}
void rotate(int x) {
    int y=f[x],z=f[y],k=get(x);
    if(!isrt(y)) ch[z][ch[z][1]==y]=x;
    ch[y][k]=ch[x][!k]; f[ch[y][k]]=y;
    ch[x][!k]=y; f[y]=x; f[x]=z;
    pushup(y); pushup(x);
}
void splay(int x) {
    update(x);
    for(int fa;fa=f[x],!isrt(x);rotate(x))
        if(!isrt(fa))
            rotate(get(fa)==get(x)?fa:x);
}
void access(int p) {
    int t=0;
    while(p) splay(p),rs=t,pushup(p),t=p,p=f[p];
}
void makeroot(int p) {
    access(p); splay(p); swap(ls,rs); rev[p]^=1;
}
void link(int x,int p) {
    makeroot(x); f[x]=p;
}
void cut(int x,int p) {
    makeroot(x); access(p); splay(p); ls=f[x]=0;
}
void split(int x,int p) {
    makeroot(x); access(p); splay(p);
}
int main() {
    scanf("%d%d",&n,&m);
    int i,x,y,z,w;
    for(i=1;i<=n;i++) val[i]=mul[i]=siz[i]=sum[i]=1;
    for(i=1;i<n;i++) {
        scanf("%d%d",&x,&y); link(x,y);
    }
    for(i=1;i<=m;i++) {
        scanf("%s%d%d",opt,&x,&y);
        int p=y;
        if(opt[0]=='+') {
            scanf("%d",&z); split(x,p);
            sum[p]=(sum[p]+siz[p]*z%mod)%mod;
            val[p]=(val[p]+z)%mod;
            add[p]=(add[p]+z)%mod;
            //cal(p,z,1,0);
        }else if(opt[0]=='-') {
            scanf("%d%d",&z,&w); cut(x,y); link(z,w);
        }else if(opt[0]=='*') {
            scanf("%d",&z); split(x,p);
            sum[p]=sum[p]*z%mod;
            val[p]=val[p]*z%mod;
            add[p]=add[p]*z%mod;
            mul[p]=mul[p]*z%mod;
            //cal(p,0,z,0);
        }else {
            split(x,p); printf("%u\n",sum[p]);
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/suika/p/8967893.html