zoukankan      html  css  js  c++  java
  • BZOJ4034 [HAOI2015]树上操作+DFS序+线段树

    参考:https://www.cnblogs.com/liyinggang/p/5965981.html

    题意:是一个数据结构题,树上的,用dfs序,变成线性的;

    思路:对于每一个节点x,记录其DFS序,包括第一次到的序号,用in【x】记录,离开的序号out【x】记录,

    再开一个数组seg,in:(序号——>节点的值);out:(序号——>节点的负值);

    这样就可以使得

      对于树来说:若所求的一个区间完全包含一个不相关子树,这个子树对结果不影响;

      对于基于 线性 的线段树来说,同时包含in【x】、out【x】区间,区间求和为0;

    利用线段树build 数组seg,得到区间的加和;

    所以,

    1-->分别更新in【x】,out【x】所对应的值;

    2-->update in【x】到out【x】区间的值;

    3-->返回 1 (根) 到 in【x】 区间的即可;

    #include <iostream>
    #include <cstdio>
    #include <vector>
    #define pb push_back
    using namespace std;
    typedef long long ll;
    const int maxn = 200050;
    ll sum[maxn*4];
    ll seg[maxn],a[maxn],lazy[maxn*4],flag[maxn*4];
    ll in[maxn],out[maxn];
    ll io[maxn];
    int cnt = 0;
    int n,m;
    vector <int> mp[maxn];
    void dfs(int u,int fa)
    {
        cnt++;
        seg[cnt] = 1ll*a[u],in[u] = 1ll*cnt;
        for(int i=0; i< mp[u].size(); i++)
        {
            int tmp  = mp[u][i];
            if(tmp == fa)continue;
            dfs(tmp,u);
        }
        cnt++;
        seg[cnt] = -1ll*a[u],out[u] = 1ll*cnt;  
        io[cnt] = -1;
    }
    void pushup(int rt)
    {
        sum[rt] = sum[rt<<1] + sum[rt<<1|1];
        flag[rt] = flag[rt<<1] + flag[rt<<1|1];
    }
    void pushdown(int rt)
    {
        if(lazy[rt])
        {
            lazy[rt<<1]  += lazy[rt]; 
            lazy[rt<<1|1]+= lazy[rt];
            sum[rt<<1]   += flag[rt<<1] * lazy[rt];    
            sum[rt<<1|1] += flag[rt<<1|1]*lazy[rt];
            lazy[rt] = 0;
        }
    }
    void build(int rt,int l,int r)
    {
        if(l==r)
        {
            sum[rt] = seg[l];
            if(io[l]==0)flag[rt] = 1;
            else flag[rt] = -1;
            return ;
        }
        int mid = (l+r)>>1;
        build(rt<<1,l,mid);
        build(rt<<1|1,mid+1,r);
        pushup(rt);
    }
        void update_one(int pos,int d,int l,int r,int rt)//单点更新;
        {
            if(l == r)
            {
                if(flag[rt] ==1 )
                    sum[rt] += d;
                else sum[rt] -= d;
                return;
            }
            pushdown(rt);
            int mid = (l+r)>>1;
            if(pos<=mid) update_one(pos,d,l,mid,rt<<1);
            else update_one(pos,d,mid+1,r,rt<<1|1);
            pushup(rt);
        }
        void update_d(int L,int R,int d,int l,int r,int rt)//区间更新;
        {
            if(l >= L && R >= r)
            {
                sum[rt] += flag[rt]*d;
                lazy[rt] += d;
                return;
            }
            pushdown(rt);
            int mid = (l+r)>>1;
            if(L<=mid) update_d(L,R,d,l,mid,rt<<1);
            if(R>mid) update_d(L,R,d,mid+1,r,rt<<1|1);
            pushup(rt);
        }
        ll query(int L,int R,int l,int r,int rt)//区间查询
        {
            if(l>=L&&r<=R)
            {
                return sum[rt];
            }
            int mid = (l+r)>>1;
            ll res = 0;
            pushdown(rt);
            if(mid>=L)res += query(L,R,l,mid,rt<<1);
            if(mid<R)res +=query(L,R,mid+1,r,rt<<1|1);
            return res;
        }
        int main(){
            scanf("%d%d",&n,&m);
            for(int i=1; i<=n;i++)
            {
                scanf("%lld" ,&a[i]);
            }
            
            for(int i=1; i<n;i++)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                mp[v].pb(u);
                mp[u].pb(v);
            }
            dfs(1,0);
            build(1,1,2*n);
            for(int i=1 ;i <= m; i++)
            {
                int op,x,val;
                scanf("%d", &op);
                if(op==1) { 
                    scanf("%d%d",&x,&val);
                    update_one(in[x],val,1,2*n,1);
                    update_one(out[x],val,1,2*n,1);
                }
                else if(op==2) {
                    scanf("%d%d",&x,&val);
                    update_d(in[x],out[x],val,1,2*n,1);
                }
                else if(op==3) {    
                    scanf("%d",&x);
                    printf("%lld
    ",query(1,in[x],1,2*n,1));
                }
            }
            return 0;
        }
  • 相关阅读:
    IDEA 编辑器如何将tabs 分行显示
    react-native-image-zoom-viewer的使用
    react native ios Linking appstore,用于更新,模拟机操作不了
    将ios的地址和安卓的地址合并生成二维码
    error: Build input file cannot be found: '/Users/zhou/Downloads/IQKeyboardManager-master/IQKeyboardManager/IQToolbar/IQUIView+IQKeyboardToolbar.m'
    react 项目中引入iconfont
    Task :react-native-yunpeng-alipay:verifyReleaseResources FAILED
    react native 支付宝接入,亲测--安卓版
    react native 支付宝接入,亲测
    iOS---------金额转大写
  • 原文地址:https://www.cnblogs.com/ckxkexing/p/8969642.html
Copyright © 2011-2022 走看看