zoukankan      html  css  js  c++  java
  • 【Luogu 3178】树上操作

    【原题题面】传送门

    【思考过程】

    树剖板子。

    说好了这题写Dfs序。

     好我已经看出来了这题用树状数组不是很好搞。

    opt1:单点修改

    opt2:区间修改

    opt3:“区间查询”

    从根节点到x的路径上的点在dfs序上的表现是:时间戳便利到当前结点,只有in还没有out,即只进入对应的子树还没有返回到自身的结点,都在当前询问结点到根节点的路径上。

    线段树维护的值有每个节点的权值,按照dfs序建线段树。

    线段树记录进栈的节点数为cnt[1]++,已出栈的节点数为cnt[0]++;

    每次更新节点时用栈内节点减去出栈节点(cnt[1]-cnt[0])来更新dat值

    【调试过程】

    dfs序两倍数组没开疯狂RE,气得我直接每个数组开long long,mxn*2...

    【code】

    #include<bits/stdc++.h>
    using namespace std;
    #define File ""
    #define ll long long
    #define ull unsigned long long
    inline void file(){
        freopen(File".in","r",stdin);
        freopen(File".out","w",stdout);
    }
    inline ll read(){
        ll x=0,f=1;   char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
        return x*f;
    }
    const int mxn = 1e5+5;
    int n,m;
    int w[mxn];
    
    struct edge{
        int nxt,y;
    }e[mxn<<1];
    int to[mxn],len;
    inline void add(int xx,int yy){
        e[++len].nxt = to[xx];
        to[xx] = len;
        e[len].y = yy;
    }
    
    bool v[mxn<<1];
    int tot(0);
    int a[mxn<<1],in[mxn<<1],ou[mxn<<1];
    inline void dfs(int x,int fa){
        a[++tot] = x;
        in[x] = tot;
        v[tot] = 1;
        for(int i = to[x]; i;i = e[i].nxt){
            int y = e[i].y;
            if(y == fa) continue;
            dfs(y,x);
        }
        a[++tot] = x;
        ou[x] = tot;
        v[tot] = 0;
    }
    
    struct T{
        int l,r,cnt[2];
        ll tg,dat;
    }tr[mxn<<4];
    #define ls p<<1
    #define rs p<<1|1
    inline void U(int p){
        tr[p].dat = tr[ls].dat + tr[rs].dat;
        tr[p].cnt[0] = tr[ls].cnt[0] + tr[rs].cnt[0];
        tr[p].cnt[1] = tr[ls].cnt[1] + tr[rs].cnt[1];
    }
    inline void build(int p,int l,int r){
        tr[p].l = l,tr[p].r = r;
        tr[p].tg = 0;
        if(l == r){
            tr[p].cnt[v[l]] ++;
            tr[p].dat = v[l] ? w[a[l]] : -w[a[l]];
            return;
        }
        int mid = l+r >>1;
        build(ls,l,mid),build(rs,mid+1,r);
        U(p);
    }
    inline void push(int p){
        ll tg = tr[p].tg;
        if(tg){
            tr[ls].tg += tg;
            tr[rs].tg += tg;
            tr[ls].dat += tg*1ll*(tr[ls].cnt[1]-tr[ls].cnt[0]);
            tr[rs].dat += tg*1ll*(tr[rs].cnt[1]-tr[rs].cnt[0]);
            tr[p].tg = 0;
        }
    }
    inline void update1(int p,int l,int r,ll d){
        if(l <= tr[p].l && tr[p].r <= r){
            tr[p].tg += d;
            tr[p].dat += d*1ll*(tr[p].cnt[1]-tr[p].cnt[0]);
            return;
        }
        push(p);
        int mid = tr[p].l + tr[p].r >>1;
        if(l <= mid) update1(ls,l,r,d);
        if(r > mid) update1(rs,l,r,d);
        U(p);
    }//区间修改
    inline ll query(int p,int l,int r){
        ll ans(0);
        if(l <= tr[p].l && tr[p].r <= r) return tr[p].dat;
        push(p);
        int mid = tr[p].l + tr[p].r >>1;
        if(l <= mid) ans += query(ls,l,r);
        if(r > mid) ans += query(rs,l,r);
        return ans;
    }
    
    int main(){
    //    file();
        scanf("%d %d",&n,&m);
        for(int i = 1;i <= n; ++i) scanf("%d",&w[i]);
        for(int i = 1;i < n; ++i){
            int x = read(),y = read();
            add(x,y),add(y,x);
        }
        memset(v,0,sizeof v);
        dfs(1,0);
        build(1,1,tot);
        for(int i = 1;i <= m; ++i){
            int opt;    scanf("%d",&opt);
            if(opt==1){
                int x;    scanf("%d",&x);
                int d = read();
                update1(1,in[x],in[x],d),update1(1,ou[x],ou[x],d);
            }else if(opt==2){
                int x = read(),d = read();
                update1(1,in[x],ou[x],d);
            }else{
                int x = read();
                printf("%lld
    ",query(1,1,in[x]));
            }
        }
        return 0;
    }
    /*
    5 5
    1 2 3 4 5
    1 2
    1 4
    2 3
    2 5
    3 3
    1 2 1
    3 5
    2 1 2
    3 3
    */
    View Code
  • 相关阅读:
    文本框改造之多选下拉控件
    多附件上传控件
    Linq to Sql:更新之属性遍历法
    如何在HTML5页面中启动本地的App? 下面的方法应该可以。
    Nodejs 学习笔记-相片整理Demo(二)
    Nodejs 学习笔记-相片整理Demo(一)
    前端学习笔记一:什么是W3C?
    网页嵌入调用 全国各城市天气代码
    html页面清除缓存
    判断鼠标动作,可以给鼠标在标签不同区域的动作分别写不同的效果
  • 原文地址:https://www.cnblogs.com/ve-2021/p/10886932.html
Copyright © 2011-2022 走看看