• ACM-ICPC 2018 沈阳赛区网络预赛 J. Ka Chang (树分块)


    题意:一个树,支持两种操作:1.将深度为L的节点权置加上X;2.求以x为根节点的子树上节点权置之和.根节点深度为0.
    分析:考虑用树状数组维护节点权置,按dfs序下标查询.记录每个深度节点的个数.如果每次都暴力维护子树上每一层的节点,则会超时.
    要用分块来解决.对于节点数量小于(sqrt{N})的层数,用树状数组维护;否则将该层记录,修改时单独记录.
    查询时,答案分成两份:树状数组中维护的子树区间的和;以及属于根为所查节点x子树,且层号是超过(sqrt{N})的节点的权置和.后者查询时,对每一个超过(sqrt{N})的层号,求其层中节点在x子树区间中的节点权置之和.

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int MAXN = 2e5+5;
    struct Edge{
        int v,next;
    }edges[MAXN<<1];
    int head[MAXN], tot,N,deep,dfs_cnt;
    int L[MAXN],R[MAXN];
    LL bit[MAXN<<1];
    vector<int> dp[MAXN];
    vector<int> bg;
    
    void init(){
        memset(bit,0,sizeof(bit));
        memset(head,-1,sizeof(head));
        tot =0;
        deep = dfs_cnt = 0;
    }
    
    void AddEdge(int u,int v){
        edges[tot] = (Edge){v,head[u]};
        head[u] = tot++;
    }
    
    void add(int pos,LL val){
        for(int i=pos; i<=N; i+= (i&-i)) bit[i] += val;
    }
    
    LL sum(int pos)
    {
        LL res=0;
        for(int i=pos; i ;i-= (i&-i)) res+= bit[i];
        return res;
    }
    
    void dfs(int u,int fa,int d)
    {
        L[u] = ++ dfs_cnt;
        deep = max(deep,d);
        dp[d].push_back(L[u]);
        for(int i=head[u];~i;i=edges[i].next){
            int v = edges[i].v;
            if(v!=fa) dfs(v,u,d+1);
        }
        R[u] = dfs_cnt;
    }
    LL ans[MAXN];
    
    int main()
    {
        #ifndef ONLINE_JUDGE
            freopen("in.txt","r",stdin);
            freopen("out.txt","w",stdout);
        #endif
        int Q,op,u,v,tmp;
        scanf("%d %d",&N, &Q);
        init();
        memset(ans,0,sizeof(ans));
        bg.clear();
        for(int i=0;i<=N;++i) dp[i].clear();
    
        for(int i=1;i<=N-1;++i){
            scanf("%d %d",&u,&v);
            AddEdge(u,v), AddEdge(v,u);
        }
        dfs(1,-1,0);
        int block = sqrt(1.0*N);
        for(int i=0;i<=deep;++i){           //该层节点大于sqrt(n)的单独保存
            if(dp[i].size()>block) bg.push_back(i);
        }
        while(Q--){
            scanf("%d",&op);
            if(op==1){
                int lev; LL x;
                scanf("%d %lld",&lev, &x);
                if(dp[lev].size()>block){       //节点数大的打上标记
                    ans[lev] += x;
                }
                else{                           //该层节点数小的直接暴力更新.
                    int siz = dp[lev].size();
                    for(int i=0;i<siz;++i){
                        add(dp[lev][i],x);
                    }
                }
            }
            else{
                scanf("%d",&u);
                LL res = sum(R[u]) - sum(L[u]-1);   //先求层数小的节点和
                int siz = bg.size();
                for(int i=0;i<siz;++i){
                    int lev = bg[i];
                    res += (upper_bound(dp[lev].begin(),dp[lev].end(),R[u])-
                    lower_bound(dp[lev].begin(),dp[lev].end(),L[u]))*ans[lev];
                }
                printf("%lld
    ",res);
            }
        }
        return 0;
    }
    
    为了更好的明天
  • 相关阅读:
    Tomcat 参数调优
    weBDrriver API接口方法小记
    cookie、session、sessionid 与jsessionid
    性能测试知多少---性能需求分析
    nvl()与regexp_replace()
    Action类的工作机制
    创建视图组件
    struts 与 Java Web应用简介
    java入门2
    java入门1
  • 原文地址:https://www.cnblogs.com/xiuwenli/p/9635699.html
Copyright © 2020-2023  润新知