BZOJ 2631: tree [LCT splay区间]

2631: tree

Time Limit: 30 Sec  Memory Limit: 128 MB
Submit: 3854  Solved: 1292
[Submit][Status][Discuss]

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


 

煞笔错误,毁我青春

把i打成x

标记和维护序列一样,只不过这次用splay而已 http://www.cnblogs.com/candy99/p/5951198.html

提取链直接写了个split,和splay的区间操作很像哈

然后usigned int即可

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define pa t[x].fa
#define lc t[x].ch[0]
#define rc t[x].ch[1]
const int N=1e5+5,MOD=51061;
typedef unsigned int ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

struct node{
    int ch[2],fa,rev,size;
    ll sum,w,add,mul;
    node():add(0),mul(1){}
}t[N];
inline int wh(int x){return t[pa].ch[1]==x;}
inline int isRoot(int x){return t[pa].ch[0]!=x&&t[pa].ch[1]!=x;}

inline void update(int x){
    t[x].sum=(t[lc].sum+t[rc].sum+t[x].w)%MOD;
    t[x].size=(t[lc].size+t[rc].size+1)%MOD;
}
inline void paint(int x,ll d,ll v){//printf("paint %d %d %d\n",x,d,v);
    t[x].add=(t[x].add*v+d)%MOD;
    t[x].mul=(t[x].mul*v)%MOD;
    t[x].w=(t[x].w*v+d)%MOD;
    t[x].sum=(t[x].sum*v+d*t[x].size)%MOD;//printf("sum %d\n",t[x].sum);
}
inline void pushDown(int x){
    if(t[x].rev){
        t[lc].rev^=1;
        t[rc].rev^=1;
        swap(lc,rc);
        t[x].rev=0;
    }
    if(t[x].add||t[x].mul!=1){
        paint(lc,t[x].add,t[x].mul);
        paint(rc,t[x].add,t[x].mul);
        t[x].add=0;
        t[x].mul=1;
    }
}
inline void rotate(int x){
    int f=t[x].fa,g=t[f].fa,c=wh(x);
    if(!isRoot(f)) t[g].ch[wh(f)]=x;t[x].fa=g;
    t[f].ch[c]=t[x].ch[c^1];t[t[f].ch[c]].fa=f;
    t[x].ch[c^1]=f;t[f].fa=x;
    update(f);update(x);
}
int st[N],top;
inline void splay(int x){
    top=0;st[++top]=x;
    for(int i=x;!isRoot(i);i=t[i].fa) st[++top]=t[i].fa;
    for(int i=top;i>=1;i--) pushDown(st[i]);
    
    for(;!isRoot(x);rotate(x))
        if(!isRoot(pa)) rotate(wh(x)==wh(pa)?pa:x);
}

inline void Access(int x){
    for(int y=0;x;y=x,x=pa){
        splay(x);
        rc=y;
        update(x);
    }
}
inline void MakeRoot(int x){
    Access(x);splay(x);
    t[x].rev^=1;
}
inline int FindRoot(int x){
    Access(x);splay(x);
    while(lc) x=lc;
    return x;
}
inline void Link(int x,int y){
    MakeRoot(x);
    t[x].fa=y;    
}
inline void Cut(int x,int y){
    MakeRoot(x);
    Access(y);splay(y);
    t[y].ch[0]=t[x].fa=0;
}
inline void split(int x,int y){
    MakeRoot(x);Access(y);splay(y);
}
int n,Q,op,x,y,c;
char s[3];
int main(){
    //freopen("in.txt","r",stdin);
    n=read();Q=read();
    for(int i=1;i<=n-1;i++) 
        x=read(),y=read(),Link(x,y),t[i].size=t[i].w=t[i].sum=1;
    t[n].size=t[n].w=t[n].sum=1;
    while(Q--){
        scanf("%s",s); x=read();y=read();
        if(s[0]=='+') c=read(),split(x,y),paint(y,c,1);
        if(s[0]=='-'){
            Cut(x,y);
            x=read();y=read();
            Link(x,y);
        }
        if(s[0]=='*') c=read(),split(x,y),paint(y,0,c);
        if(s[0]=='/') split(x,y),printf("%d\n",t[y].sum);
    }
}

 

 

posted @ 2017-01-11 19:02  Candy?  阅读(280)  评论(0编辑  收藏  举报