2018 ICPC shenyang online J KaChang(分块+dfs序+BIT)

题意:

给你一颗根节点为1(深度为0)的树,初始每个节点的point为0。给定两种操作

  1. 1 l x 将所有深度为l的节点point+x。
  2. 2 x   输出以x为根的子树的point和。

思路:

1操作很难搞啊!分块

按每一层的节点个数分类讨论,设阈值为T。

对于操作1,当第L层的节点个数SizeL 当L层的节点数SizeL>=T时,显然这样的层数不超过\frac{N}{T}个,可以直接对每个这样的层维护增加了多少point,询问时枚举一遍即可

第一种情况,用BIT维护dfs序上的区间和,时间复杂度O(Q*(T*logN))。
第二种情况,我是直接标记。留到询问时处理。

对于询问 第一种情况可以用BIT logN 查询 再加上第二种情况:
枚举所有Size>T的层数,二分查找每个层中有多少个属于x子树的几点乘以该层的增加值。
时间复杂度大概是O(Q*(logN+(N/T)*logN))。

试了试T为sqrt(n)和n/log(n)差别不大。

 

#include
using namespace std;
typedef long long ll;

const int maxn = 1e5+5;

vector G[maxn],dep[maxn],mle;
ll lazy[maxn];
int st[maxn],ed[maxn],timing,maxdeep;
int n,q,block;
void dfs(int u,int deep){
    maxdeep=max(deep,maxdeep);
    st[u] = ++timing;
    dep[deep].push_back(timing);
    for(int v : G[u]){
        dfs(v,deep+1);
    }
    ed[u] = timing;
}
//BIT-----------------
ll c[maxn];
int lowbit(int x){return x&(-x);}
void add(int i,int v){
    for(;i0;i-=lowbit(i))
        res += c[i];
    return res;
}

void work(){
    int op,l,x;
    scanf("%d",&op);
    if(op==1) {
        scanf("%d%d",&l,&x);
        if(dep[l].size()= block){
            mle.push_back(i);
        }
    }
    while(q--){
        work();
    }
    return 0;
}

 

 

 

Reference:https://www.cnblogs.com/Rickenqi/p/9635938.html

你可能感兴趣的:(分块)