• bzoj4034 线段树+dfs序


    https://www.lydsy.com/JudgeOnline/problem.php?id=4034

    有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
    操作,分为三种:
    操作 1 :把某个节点 x 的点权增加 a 。
    操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
    操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
     
    dfs序真是一个奥妙重重的东西
    首先求出dfs序,操作1显然是一个单点修改,操作2显然是一个区间修改,我们看到我们要询问的事实上是一条链的和,我们就不能简单地进行单点修改和区间修改,事实上1到x的点在dfs序上可以视为一个栈,第一次出现是进栈,第二次出现时出栈,我们只要将进栈的点权为正,出栈的点权为负,线段树进行一波区间修改和区间查询即可。
    #include <map>
    #include <set>
    #include <ctime>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <string>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    using namespace std;
    inline int read(){int now=0;register char c=getchar();for(;!isdigit(c);c=getchar());
    for(;isdigit(c);now=now*10+c-'0',c=getchar());return now;}
    #define For(i, x, y) for(int i=x;i<=y;i++)  
    #define _For(i, x, y) for(int i=x;i>=y;i--)
    #define Mem(f, x) memset(f,x,sizeof(f))  
    #define Sca(x) scanf("%d", &x)
    #define Sca2(x,y) scanf("%d%d",&x,&y)
    #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
    #define Scl(x) scanf("%lld",&x);  
    #define Pri(x) printf("%d
    ", x)
    #define Prl(x) printf("%lld
    ",x);  
    #define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
    #define LL long long
    #define ULL unsigned long long  
    #define mp make_pair
    #define PII pair<int,int>
    #define PIL pair<int,long long>
    #define PLL pair<long long,long long>
    #define pb push_back
    #define fi first
    #define se second 
    typedef vector<int> VI;
    const double eps = 1e-9;
    const int maxn = 4e5 + 10;
    const int INF = 0x3f3f3f3f;
    const int mod = 1e9 + 7; 
    int N,M,K;
    LL val[maxn];
    struct Edge{
        int to,next;
    }edge[maxn * 2];
    int head[maxn],tot;
    void init(){Mem(head,-1); tot = 0;}
    void add(int u,int v){edge[tot].to = v;edge[tot].next = head[u];head[u] = tot++;}
    PII Index[maxn * 2];
    PII pos[maxn];
    int id = 0;
    void dfs(int t,int fa){
        Index[++id].fi = t;
        Index[id].se = 1;
        pos[t].fi = id;
        for(int i = head[t]; ~i; i = edge[i].next){
            int v = edge[i].to;
            if(v == fa) continue;
            dfs(v,t);
        }
        Index[++id].fi = t;
        Index[id].se = -1;
        pos[t].se = id;
    }
    struct Tree{
        int l,r;
        int up,down;
        LL sum,lazy;
    }tree[maxn << 2];
    void Pushup(int t){
        tree[t].sum = tree[t << 1].sum + tree[t << 1 | 1].sum;
    }
    void Build(int t,int l,int r){
        tree[t].l = l; tree[t].r = r;
        tree[t].up = tree[t].down = tree[t].lazy = 0;
        if(l == r){
            if(Index[l].se == 1){
                tree[t].sum = val[Index[l].fi];
                tree[t].up++;
            }else{
                tree[t].sum = -val[Index[l].fi];
                tree[t].down++;
            }
            return ;
        }
        int m = (l + r) >> 1;
        Build(t << 1,l,m); Build(t << 1 | 1,m + 1,r);
        Pushup(t);
        tree[t].up = tree[t << 1].up + tree[t << 1 | 1].up;
        tree[t].down = tree[t << 1].down + tree[t << 1 | 1].down; 
    }
    void Pushdown(int t){
        if(tree[t].lazy){
            tree[t << 1].sum += (tree[t << 1].up - tree[t << 1].down) * tree[t].lazy;
            tree[t << 1 | 1].sum += (tree[t << 1 | 1].up - tree[t << 1 | 1].down) * tree[t].lazy;
            tree[t << 1].lazy += tree[t].lazy; tree[t << 1 | 1].lazy += tree[t].lazy;
            tree[t].lazy = 0;
        }
    }
    void update(int t,int l,int r,LL a){
        if(l <= tree[t].l && tree[t].r <= r){
            tree[t].sum += (tree[t].up - tree[t].down) * a;
            tree[t].lazy += a;
            return;
        }
        Pushdown(t);
        int m = (tree[t].l + tree[t].r) >> 1;
        if(r <= m) update(t << 1,l,r,a);
        else if(l > m) update(t << 1 | 1,l,r,a);
        else{
            update(t << 1,l,m,a);
            update(t << 1 | 1,m + 1,r,a);
        }
        Pushup(t);
    }
    LL query(int t,int l,int r){
        if(l > r) return 0;
        if(l <= tree[t].l && tree[t].r <= r){
            return tree[t].sum;
        }
        Pushdown(t);
        int m = (tree[t].l + tree[t].r) >> 1;
        if(r <= m) return query(t << 1,l,r);
        else if(l > m) return query(t << 1 | 1,l,r);
        else{
            return query(t << 1,l,m) + query(t << 1 | 1,m + 1,r);
        }
    }
    int main()
    {
        Sca2(N,M); init();
        For(i,1,N) Scl(val[i]);
        For(i,1,N - 1){ int u,v; Sca2(u,v); add(u,v); add(v,u);}
        int root = 1; id = 0;
        dfs(root,-1);
        Build(1,1,2 * N); 
        while(M--){
            int op = read();
            if(op == 1){
                int x; Sca(x); LL a; Scl(a);
                update(1,pos[x].fi,pos[x].fi,a); update(1,pos[x].se,pos[x].se,a);
            }else if(op == 2){
                int x; Sca(x); LL a; Scl(a);
                update(1,pos[x].fi,pos[x].se,a);
            }else{
                int x; Sca(x);
                Prl(query(1,1,pos[x].fi));
            }
        }
        #ifdef VSCode
        system("pause");
        #endif
        return 0;
    }
  • 相关阅读:
    CommonJs、AMD、CMD模块化规范
    在 repeater控件中有button控件,如何点击button按钮在后头产生方法
    DropdownList动态绑定数据库中的字段
    电脑操作的快捷键
    多条件查询
    asp.Net_图片上传的一个类库的源码
    日期转换_中文To数字
    VS2010断点设置技巧
    附加进程调试
    电脑常用的几个快捷键
  • 原文地址:https://www.cnblogs.com/Hugh-Locke/p/9843009.html
Copyright © 2020-2023  润新知