[ACM-ICPC 2018 沈阳网络赛] Ka Chang (dfs序+树状数组+分块)

Posted zhangbuang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ACM-ICPC 2018 沈阳网络赛] Ka Chang (dfs序+树状数组+分块)相关的知识,希望对你有一定的参考价值。

Given a rooted tree ( the root is node 11 ) of NN nodes. Initially, each node has zero point.

Then, you need to handle QQ operations. There‘re two types:

1\ L\ X1 L X: Increase points by XX of all nodes whose depth equals LL ( the depth of the root is zero ). (x \leq 10^8)(x108)

2\ X2 X: Output sum of all points in the subtree whose root is XX.

Input

Just one case.

The first lines contain two integer, N,QN,Q. (N \leq 10^5, Q \leq 10^5)(N105,Q105).

The next n-1n1 lines: Each line has two integer aa,bb, means that node aa is the father of node bb. It‘s guaranteed that the input data forms a rooted tree and node 11 is the root of it.

The next QQ lines are queries.

Output

For each query 22, you should output a number means answer.

样例输入

3 3
1 2
2 3
1 1 1
2 1
2 3

样例输出

1
0

SOLUTION:

第一次写分块这种的暴力的方法qwq
发现本题 查询子树和 与 修改相同深度的点的val时相互矛盾的
那就考虑怎么暴力吧

即,如果修改的那个层数的节点小于某个T,那么就直接用树状数组+DFS序维护子树和,暴力单点更新。

如果 大于> ,那么就用懒惰标记的思想,先把加了多少 记录下来,等查询的时候再暴力查询该子树,深度为某个值的节点个数,然后乘以该懒惰标记即可。那么这个T多大呢?明显是sqrt(N)。

那么查询某子树,深度为某个值的节点个数怎么做呢?先把节点按照dfs序编号,然后记录某层有哪些节点,最后二分查询即可。

CODE:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
typedef long long ll;

vector<int>G[maxn],dep[maxn],large;
int st[maxn],ed[maxn],tim,n;
ll tree[maxn],num[maxn];

void add(int pos,ll v)

    for(;pos<=n;pos+=pos&-pos)
        tree[pos]+=v;


ll query(int pos)

    ll ans=0;
    for(;pos;pos-=pos&-pos)
        ans+=tree[pos];
    return ans;


void dfs(int u,int fa,int depth) //时间戳

    st[u]=++tim;
    dep[depth].push_back(tim);
    int sz=G[u].size();
    for(int i=0;i<sz;i++)
        if(G[u][i]!=fa)
            dfs(G[u][i],u,depth+1);
    ed[u]=tim;


int main()

    int q;
    scanf("%d%d",&n,&q);
    for(int i=0;i<n-1;i++)
    
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    
    dfs(1,0,0);

    int block=ceil(sqrt(n));
    for(int i=0;i<n;i++)
        if(dep[i].size()>block)
            large.push_back(i);

    while(q--)
    
        int nood;
        scanf("%d",&nood);
        if(nood==1)
        
            int depth;
            ll v;
            scanf("%d%lld",&depth,&v);
            if(dep[depth].size()>block) num[depth]+=v;
            else
            
                for(int i=0;i<dep[depth].size();i++)
                    add(dep[depth][i],v);
            
        
        else
        
            int x;
            scanf("%d",&x);
            ll ans=query(ed[x])-query(st[x]-1);
            for(int i=0;i<large.size();i++)
                ans+=(upper_bound(dep[large[i]].begin(),dep[large[i]].end(),ed[x])-lower_bound(dep[large[i]].begin(),dep[large[i]].end(),st[x]))*num[large[i]];
            printf("%lld\n",ans);
        
    

  

 








以上是关于[ACM-ICPC 2018 沈阳网络赛] Ka Chang (dfs序+树状数组+分块)的主要内容,如果未能解决你的问题,请参考以下文章

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

ACM-ICPC 2018 沈阳赛区网络预赛 J. Ka Chang(树上分块+dfs序+线段树)

[ACM-ICPC 2018 沈阳网络赛] G. Spare Tire (思维+容斥)

2019ACM-ICPC沈阳网络赛-C-Dawn-K's water(完全背包模板题)

2019ACM-ICPC沈阳网络赛-K-Guanguan's Happy water(思维+暴力)

ACM-ICPC 2018 沈阳赛区网络预赛