zoukankan      html  css  js  c++  java
  • BZOJ 2631 tree | Luogu P1501 [国家集训队]Tree II (LCT 多重标记下放)

    链接:https://www.luogu.org/problemnew/show/P1501

    题面:

    题目描述

    一棵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行,每行描述一个操作

    输出格式:

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

    输入输出样例

    输入样例#1: 复制
    3 2
    1 2
    2 3
    * 1 3 4
    / 1 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

    By (伍一鸣)

    思路:

    写法跟线段树差不多,修改i下pushdown多维护连个标记就好了。

    实现代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ls c[x][0]
    #define rs c[x][1]
    const int M = 4e5+10;
    const int inf = 1e9;
    const int mod = 51061;
    int top;
    int sum[M],c[M][2],val[M],fa[M],rev[M],mn[M],S[M],tmp[M];
    int siz[M],mul[M],add[M];
    inline void up(int x){
        //cout<<sum[x]<<" "<<sum[ls]<<" "<<sum[rs]<<" "<<val[x]<<endl;
        sum[x] = (sum[ls] + sum[rs] + val[x])%mod;
        siz[x] = (siz[ls] + siz[rs] + 1)%mod;;
    }
    
    inline void pushrev(int x){
        swap(ls,rs); rev[x] ^= 1;
    }
    
    inline void pushmul(int x,int c){
        mul[x] = (1LL*mul[x]*c)%mod;
        add[x] = (1LL*add[x]*c)%mod;
        sum[x] = (1LL*sum[x]*c)%mod;
        val[x] = (1LL*val[x]*c)%mod;
        //cout<<mul[x]<<" "<<val[x]<<endl;
    }
    
    inline void pushadd(int x,int c){
        add[x] = (add[x] + c)%mod;
        val[x] = (val[x] + c)%mod;
        sum[x] = (1LL*sum[x]+1LL*siz[x]*c)%mod;
    }
    
    inline bool isroot(int x){
        return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
    }
    
    inline void rotate(int x){
        int y = fa[x],z = fa[y];
        int k = c[y][1] == x;
        if(!isroot(y)) c[z][c[z][1]==y]=x;
        fa[x] = z;
        c[y][k] = c[x][k^1]; fa[c[x][k^1]] = y;
        c[x][k^1] = y; fa[y] = x;
        up(y); up(x);
    }
    
    inline void pushdown(int x){
        if(rev[x]){
            if(ls) pushrev(ls);
            if(rs) pushrev(rs);
            rev[x] = 0;
        }
        if(mul[x]!=1){
            if(ls) pushmul(ls,mul[x]);
            if(rs) pushmul(rs,mul[x]);
            mul[x] = 1;
        }
        if(add[x]){
            if(ls) pushadd(ls,add[x]);
            if(rs) pushadd(rs,add[x]);
            add[x] = 0;
        }
    }
    
    inline void splay(int x){
        S[top=1]=x;
        for(int i = x;!isroot(i);i=fa[i]) S[++top] = fa[i];
        while(top) pushdown(S[top--]);
        while(!isroot(x)){
            int y = fa[x],z = fa[y];
            if(!isroot(y))
                (c[y][1]==x)^(c[z][1]==y)?rotate(x):rotate(y);
            rotate(x);
        }
    }
    
    inline void access(int x){
        for(int y = 0;x;y = x,x = fa[x])
            splay(x),c[x][1] = y,up(x);
    }
    
    inline void makeroot(int x){
        access(x); splay(x); pushrev(x);
    }
    
    inline void split(int x,int y){
        makeroot(x); access(y); splay(y);
    }
    
    inline void link(int x,int y){
        makeroot(x);fa[x] = y;
    }
    
    inline void cut(int x,int y){
        split(x,y); fa[x] = c[y][0] = 0; up(y);
    }
    
    inline int findroot(int x){
        access(x); splay(x);
        while(ls) x = ls;
        return x;
    }
    
    int main()
    {
        int n,q,u,v,x,y,k;
        scanf("%d%d",&n,&q);
        for(int i = 1;i <= n;i ++) val[i] = mul[i] = 1;
        for(int i = 1;i < n;i ++){
            scanf("%d%d",&u,&v);
            link(u,v);
        }
        char op[10];
        while(q--){
            scanf("%s",op);
            scanf("%d%d",&u,&v);
            if(op[0] == '+') {
                scanf("%d",&k);
                split(u,v); pushadd(v,k);
            }
            else if(op[0] == '-'){
                scanf("%d%d",&x,&y);
                cut(u,v); link(x,y);
            }
            else if(op[0] == '*'){
                scanf("%d",&k);
                split(u,v); pushmul(v,k);
            }
            else if(op[0] == '/'){
                //cout<<u<<" "<<v<<endl;
                split(u,v); printf("%d
    ",sum[v]);
            }
        }
        return 0;
    }
  • 相关阅读:
    window安装swagger editor
    DiffMerge安装配置使用
    线程池相关知识点
    JAVA程序员面试笔试宝典4
    JAVA程序员面试笔试宝典3
    JAVA程序员面试笔试宝典2
    JAVA程序员面试笔试宝典1
    Linux开启ssh服务
    面试题
    java基础学习之垃圾回收机制
  • 原文地址:https://www.cnblogs.com/kls123/p/10796586.html
Copyright © 2011-2022 走看看