首页 > 代码库 > bzoj 2631: tree 动态树+常数优化

bzoj 2631: tree 动态树+常数优化

2631: tree

Time Limit: 30 Sec  Memory Limit: 128 MB
Submit: 1716  Solved: 576
[Submit][Status]

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

 

  动态树编的还是不熟练,这道题的模数是刚刚爆int的(51061^2==2607225721>2147483647),如果用long long 又要TLE,所以必须用unsigned int.

  这道题涉及到动态树的路径操作,具体用法是通过make_root()access()将一个路径上所有点集中到一个splay中。

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<ctime>#include<cmath>#include<algorithm>#include<set>#include<map>#include<vector>#include<string>#include<queue>using namespace std;#ifdef WIN32#define LL "%I64d"#else#define LL "%lld"#endif#define MAXN 110000#define MAXT MAXN*2#define MAXV MAXN*2#define MAXE MAXV*2#define INF 0x3f3f3f3f#define INFL 0x3f3f3f3f3f3f3f3fLL#define lch ch[now][0]#define rch ch[now][1]#define plus _plus#define MOD 51061//刚刚爆inttypedef unsigned int qword;inline int nextInt(){        char ch;        int x=0;        bool flag=false;        do                ch=(char)getchar(),flag=(ch==-)?true:flag;        while(ch<0||ch>9);        do x=x*10+ch-0;        while (ch=(char)getchar(),ch<=9 && ch>=0);        return x*(flag?-1:1);}int n,m;struct Edge{        int np;        Edge *next;}E[MAXE],*V[MAXV];int tope=-1;int fa[MAXT];int depth[MAXT];inline void addedge(int x,int y){        E[++tope].np=y;        E[tope].next=V[x];        V[x]=&E[tope];}void dfs(int now){        Edge *ne;        for (ne=V[now];ne;ne=ne->next)        {                if (ne->np==fa[now])continue;                fa[ne->np]=now;                depth[ne->np]=depth[now]+1;                dfs(ne->np);        }}//------------------------Link Cut Tree------------------------int pnt[MAXT],ch[MAXT][2];qword sum[MAXT],val[MAXT];qword mult[MAXT],plus[MAXT];bool flip[MAXT];int stack[MAXT],tops=-1;int siz[MAXT];void init(){        int i;        for (i=1;i<=n;i++)        {                pnt[i]=fa[i];                mult[i]=1;                plus[i]=0;                val[i]=sum[i]=1;                flip[i]=false;                siz[i]=1;        }}inline bool is_root(int now)//是splay上的根{        return (!pnt[now]) || (ch[pnt[now]][0]!=now && ch[pnt[now]][1]!=now);}inline void up(int now){        sum[now]=(sum[lch]+sum[rch]+val[now])%MOD;        siz[now]=(siz[lch]+siz[rch]+1)%MOD;}inline void reverse(int now){        if (!now)return;        swap(ch[now][0],ch[now][1]);        flip[now]^=1;}inline void make_multiply(int now,qword v)//对于一个splay的子树加标记下放{        mult[now]=mult[now]*v%MOD;        plus[now]=plus[now]*v%MOD;        sum[now]=sum[now]*v%MOD;        val[now]=val[now]*v%MOD;}inline void make_plus(int now,qword v)//同make_multiply{        plus[now]=(plus[now]+v)%MOD;        sum[now]=(sum[now]+v*siz[now])%MOD;        val[now]=(val[now]+v)%MOD;}inline void down(int now){        if (flip[now])        {                reverse(ch[now][0]);                reverse(ch[now][1]);                flip[now]=false;        }        if (mult[now]!=1)        {                make_multiply(ch[now][0],mult[now]);                make_multiply(ch[now][1],mult[now]);                mult[now]=1;        }        if (plus[now])        {                make_plus(ch[now][0],plus[now]);                make_plus(ch[now][1],plus[now]);                plus[now]=0;        }}inline void rotate(int now){        int p=pnt[now],anc=pnt[p];        if (is_root(now))throw 1;        int dir=ch[p][0]==now;        pnt[now]=anc;        if (!is_root(p))/**/                ch[anc][ch[anc][1]==p]=now;        ch[p][1-dir]=ch[now][dir];        pnt[ch[now][dir]]=p;        pnt[p]=now;        ch[now][dir]=p;        up(p);        up(now);}void splay(int now){        int x=now;        while (!is_root(x))        {                stack[++tops]=x;                x=pnt[x];        }        stack[++tops]=x;        do{                down(stack[tops--]);        }while (tops>=0);        if (is_root(now))return ;//先下放标记,否则access中自动接在其他点上面        while (!is_root(now))        {                int p=pnt[now],anc=pnt[p];                if (is_root(p))//注意判断的对象                {                        rotate(now);                }else                {                        if ((ch[anc][0]==p) == (ch[p][0]==now))                        {                                rotate(p);                                rotate(now);                        }else                        {                                rotate(now);                                rotate(now);                        }                }        }}void access(int now)//需要记忆!{        int son=0;        for (;now;now=pnt[son=now])        {                splay(now);                ch[now][1]=son;                up(now);        }//        while (ch[now][0])//                now=ch[now][0];//        return now;}void make_root(int now){        access(now);        splay(now);        swap(ch[now][0],ch[now][1]);        reverse(ch[now][0]);        reverse(ch[now][1]);        //reverse(now);//注意}void cut(int x,int y){        make_root(x);        access(y);        splay(x);        ch[x][ch[x][1]==y]=0;        pnt[y]=0;        up(x);        up(y);}void link(int x,int y){//        access(y);        splay(y);        make_root(x);        access(x);        splay(x);        pnt[x]=y;        up(y);}void scan(int now){        if (!now)return ;        down(now);        scan(lch);        printf("%d ",(int)val[now]);        scan(rch);}int main(){        //freopen("input.txt","r",stdin);        //freopen("output.txt","w",stdout);        int i;        int x,y,z;        int a,b,c,d;        scanf("%d%d",&n,&m);        for (i=1;i<n;i++)        {                x=nextInt();y=nextInt();                //scanf("%d%d",&x,&y);                addedge(x,y);                addedge(y,x);        }        scanf("\n");        dfs(1);        init();        char opt;        for (i=0;i<m;i++)        {                opt=(int)getchar();                //scanf("%c",&opt);                if (opt==+)                {                        x=nextInt();y=nextInt();z=nextInt();                        //scanf("%d%d%d\n",&x,&y,&z);                        z%=MOD;                        make_root(x);                        access(y);                        splay(y);                        make_plus(y,z);                }else if (opt==-)                {                        a=nextInt();b=nextInt();c=nextInt();d=nextInt();                        //scanf("%d%d%d%d\n",&a,&b,&c,&d);                        cut(a,b);                        link(c,d);                }else if (opt==*)                {                        x=nextInt();y=nextInt();z=nextInt();                        //scanf("%d%d%d\n",&x,&y,&z);                        z%=MOD;                        make_root(x);                        access(y);                        splay(y);                        make_multiply(y,z);                }else if (opt==/)                {                        x=nextInt();y=nextInt();                        //scanf("%d%d\n",&x,&y);                        make_root(x);                        access(y);                        splay(y);                        printf("%d\n",(int)sum[y]);                }        }        return 0;}

 

bzoj 2631: tree 动态树+常数优化