zoukankan      html  css  js  c++  java
  • C A National Pandemic(树上点扩减值,树剖)

    题:https://ac.nowcoder.com/acm/contest/5672/C

    题意:给定树,m个操作:(1)在x点处增加w,树上每个点y的值+=w-dis(x,y)。

                (2)将x点处值和0取min

                (3)查询x点的值

    分析:将每个点x 的值展开=w-dep(x)-dep(y)+2*dep(lca)。我分成(w-dep(x)),-(dep(y)),(2*dep(lca))来算

       对于前俩部分我们很容易在边操作时边统计出来,对于第三部分我们用树剖维护,若在x进行1操作,那么就在x与根节点路径上的所有点都加2,查询就查询出的x'到根节点路径和就是第三部分的值(因为若要查询当前的x',x'与之前x的lca的dep*2就为lca到根节点路径长*2)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define pb push_back
    #define lson root<<1,l,midd
    #define rson root<<1|1,midd+1,r
    const int inf=0x3f3f3f3f;
    const ll INF=1e18;
    const int M=2e5+5;
    const int mod=998244353;
    
    vector<int>g[M];
    int n,m,tot,sz[M],fa[M],id[M],son[M],top[M],dep[M];
    int tr[M<<2],lz[M<<2];
    int lasans[M],lasans1[M],lasnum[M];
    void dfs1(int u,int f){
        sz[u]=1,fa[u]=f;
        dep[u]=dep[f]+1;
        for(auto v:g[u]){
            if(v!=f){
                dfs1(v,u);
                sz[u]+=sz[v];
                if(!son[u]||sz[v]>sz[son[u]])
                    son[u]=v;
            }
        }
    }
    void dfs2(int u,int tp){
        id[u]=++tot,top[u]=tp;
        if(son[u])
            dfs2(son[u],tp);
        for(auto v:g[u]){
            if(v!=fa[u]&&v!=son[u])
                dfs2(v,v);
        }
    }
    void build(int root,int l,int r){
        tr[root]=lz[root]=0;
        if(l==r)return;
        int midd=(l+r)>>1;
        build(lson);
        build(rson);
    }
    void up(int root){
        tr[root]=tr[root<<1]+tr[root<<1|1];
    }
    void pushdown(int root,int l,int r){
        if(lz[root]){
            int midd=(l+r)>>1;
            tr[root<<1]+=(midd-l+1)*2*lz[root];
            tr[root<<1|1]+=(r-midd)*2*lz[root];
    
            lz[root<<1]+=lz[root];
            lz[root<<1|1]+=lz[root];
            lz[root]=0;
            return ;
        }
    }
    void update(int L,int R,int root,int l,int r){
        if(L<=l&&r<=R){
            tr[root]+=(r-l+1)*2;
            lz[root]++;
            return ;
        }
        pushdown(root,l,r);
        int midd=(l+r)>>1;
        if(L<=midd)
            update(L,R,lson);
        if(R>midd)
            update(L,R,rson);
        up(root);
    }
    int query(int L,int R,int root,int l,int r){
        ///cout<<l<<"##"<<r<<endl;
        if(L<=l&&r<=R){
            return tr[root];
        }
        int midd=(l+r)>>1;
        pushdown(root,l,r);
        int res=0;
        if(L<=midd)
            res+=query(L,R,lson);
        if(R>midd)
            res+=query(L,R,rson);
        return res;
    }
    void solve1(int u){
        while(u){
            update(id[top[u]],id[u],1,1,n);
            u=fa[top[u]];
        }
    }
    int solve2(int u){
        int ans=0;
        while(u){
            ans+=query(id[top[u]],id[u],1,1,n);
            u=fa[top[u]];
        }
        return ans;
    }
    int main(){
        int T;
        scanf("%d",&T);
        while(T--){
            scanf("%d%d",&n,&m);
            tot=0;
            for(int i=0;i<=n;i++)
                g[i].clear(),lasans[i]=lasans1[i]=lasnum[i]=0,son[i]=0;
            for(int u,v,i=1;i<n;i++){
                scanf("%d%d",&u,&v);
                g[u].pb(v),g[v].pb(u);
            }
            dfs1(1,0);
            dfs2(1,1);
            build(1,1,n);
            int ans1=0;
            int num=0;///1操作插入的点数
            while(m--){
                int op,x,w;
                scanf("%d%d",&op,&x);
                if(op==1){
                    scanf("%d",&w);
                    solve1(x);
                    ans1+=w-dep[x];
                    num++;
                }
                else if(op==2){
                    int ans2=solve2(x);
                    int ans=lasans[x]+(ans1-lasans1[x])-(num-lasnum[x])*dep[x]+ans2;
                    if(ans<=0)
                        lasans[x]=ans-ans2;///保持不变,所以保持前俩项
                    else
                        lasans[x]=-ans2;///全不要,而ans2是单独算的,所以在下次算的时候会抵消这次-的
                    lasans1[x]=ans1;
                    lasnum[x]=num;
                }
                else{
                    int ans2=solve2(x);
                    int ans=lasans[x]+(ans1-lasans1[x])-(num-lasnum[x])*dep[x]+ans2;
                    lasans[x]=ans-ans2;
                    lasans1[x]=ans1;
                    lasnum[x]=num;
                    printf("%d
    ",ans);
                }
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Murano Weekly Meeting 2015.11.04
    Python pdb调试
    Neutron命令测试5
    Neutron命令测试4
    Neutron命令测试3
    Neutron命令测试2
    Neutron命令测试1
    Murano Weekly Meeting 2015.10.20
    Murano Weekly Meeting 2015.10.13
    wireshark分析dhcp过程
  • 原文地址:https://www.cnblogs.com/starve/p/13418770.html
Copyright © 2011-2022 走看看