zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    ASP.NET Web API 控制器执行过程(一)
    ASP.NET Web API 控制器创建过程(二)
    ASP.NET Web API 控制器创建过程(一)
    ASP.NET Web API WebHost宿主环境中管道、路由
    ASP.NET Web API Selfhost宿主环境中管道、路由
    ASP.NET Web API 管道模型
    ASP.NET Web API 路由对象介绍
    ASP.NET Web API 开篇示例介绍
    ASP.NET MVC 视图(五)
    ASP.NET MVC 视图(四)
  • 原文地址:https://www.cnblogs.com/mhy12345/p/4032185.html
Copyright © 2011-2022 走看看