zoukankan      html  css  js  c++  java
  • BZOJ2631tree——LCT

    题目描述

     一棵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的余数。

    输入

      第一行两个整数n,q
    接下来n-1行每行两个正整数u,v,描述这棵树
    接下来q行,每行描述一个操作

    输出

      对于每个/对应的答案输出一行

    样例输入

    3 2
    1 2
    2 3
    * 1 3 4
    / 1 1

    样例输出

    4

    提示

    数据规模和约定

    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,splay每个点维护子树和,单点权值和两个区间修改标记,注意加法和乘法运算顺序即可。开unsigned int即可,开longlong可能会T。

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<bitset>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll unsigned int
    using namespace std;
    int n,m;
    int x,y,z,w;
    int mod=51061;
    char ch[2];
    int f[100010];
    int s[100010][2];
    int st[100010];
    int r[100010];
    int size[100010];
    ll sum[100010];
    ll val[100010];
    ll a[100010];
    ll b[100010];
    int get(int rt)
    {
        return rt==s[f[rt]][1];
    }
    void change(int rt,int x,int y)
    {
        if(!rt)
        {
            return ;
        }
        sum[rt]=(sum[rt]*x+y*size[rt])%mod;
        val[rt]=(val[rt]*x+y)%mod;
        a[rt]=(a[rt]*x+y)%mod;
        b[rt]=(b[rt]*x)%mod;
    }
    void pushup(int rt)
    {
        sum[rt]=(sum[s[rt][0]]+sum[s[rt][1]]+val[rt])%mod;
        size[rt]=(size[s[rt][0]]+size[s[rt][1]]+1)%mod;
    }
    void pushdown(int rt)
    {
        if(r[rt])
        {
            swap(s[rt][0],s[rt][1]);
            r[s[rt][0]]^=1;
            r[s[rt][1]]^=1;
            r[rt]^=1;
        }
        int x=a[rt];
        int y=b[rt];
        a[rt]=0;
        b[rt]=1;
        if(x!=0||y!=1)
        {
            change(s[rt][0],y,x);
            change(s[rt][1],y,x);
        }
    }
    int is_root(int rt)
    {
        return s[f[rt]][0]!=rt&&s[f[rt]][1]!=rt;
    }
    void rotate(int rt)
    {
        int fa=f[rt];
        int anc=f[fa];
        int k=get(rt);
        if(!is_root(fa))
        {
            s[anc][fa==s[anc][1]]=rt;
        }
        s[fa][k]=s[rt][k^1];
        f[s[fa][k]]=fa;
        s[rt][k^1]=fa;
        f[fa]=rt;
        f[rt]=anc;
        pushup(fa);
        pushup(rt);
    }
    void splay(int rt)
    {
        int top=0;
        st[++top]=rt;
        for(int i=rt;!is_root(i);i=f[i])
        {
            st[++top]=f[i];
        }
        for(int i=top;i>=1;i--)
        {
            pushdown(st[i]);
        }
        for(int fa;!is_root(rt);rotate(rt))
        {
            if(!is_root(fa=f[rt]))
            {
                rotate(get(rt)==get(fa)?fa:rt);
            }
        }
    }
    void access(int rt)
    {
        for(int x=0;rt;x=rt,rt=f[rt])
        {
            splay(rt);
            s[rt][1]=x;
            pushup(rt);
        }
    }
    void reverse(int rt)
    {
        access(rt);
        splay(rt);
        r[rt]^=1;
    }
    void split(int x,int y)
    {
        reverse(x);
        access(y);
        splay(y);
    }
    void link(int x,int y)
    {
        reverse(x);
        f[x]=y;
    }
    void cut(int x,int y)
    {
        reverse(x);
        access(y);
        splay(y);
        s[y][0]=f[x]=0;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            size[i]=val[i]=sum[i]=b[i]=1;
        }
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            link(x,y);
        }
        while(m--)
        {
            scanf("%s",ch);
            scanf("%d%d",&x,&y);
            if(ch[0]=='+')
            {
                scanf("%d",&z);
                split(x,y);
                change(y,1,z);
            }
            else if(ch[0]=='-')
            {
                scanf("%d%d",&w,&z);
                cut(x,y);
                link(w,z);
            }
            else if(ch[0]=='*')
            {
                scanf("%d",&z);
                split(x,y);
                change(y,z,0);
            }
            else if(ch[0]=='/')
            {
                split(x,y);
                printf("%d
    ",sum[y]);
            }
        }
    }
  • 相关阅读:
    闭包概念集合
    对象的基本方法
    webpack始出来
    elasticsearch性能调优
    elasticsearch 倒排索引学习
    elasticearch 归并策略
    更加详细的Log4net的配置
    第一篇博客关于Log4net的配置记录
    js数组小结
    javascript在不同的浏览器处理事件
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/9744732.html
Copyright © 2011-2022 走看看