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中。

  还有一点,就是这类支持区间加,乘的题,标记应即为x*mul+plus,即先下放mul,在下放plus

#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//刚刚爆int
typedef 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("
");
        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
",&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
",&a,&b,&c,&d);
                        cut(a,b);
                        link(c,d);
                }else if (opt=='*')
                {
                        x=nextInt();y=nextInt();z=nextInt();
                        //scanf("%d%d%d
",&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
",&x,&y);
                        make_root(x);
                        access(y);
                        splay(y);
                        printf("%d
",(int)sum[y]);
                }
        }
        return 0;
}
by mhy12345(http://www.cnblogs.com/mhy12345/) 未经允许请勿转载

本博客已停用,新博客地址:http://mhy12345.xyz

原文地址:https://www.cnblogs.com/mhy12345/p/4032185.html