P3899 | Chairman tree + dfs order

After understanding the problem in two cases:
1.b at the top of a: min (dep [p] -1 , k) * (ll) siz [p] as above (p point there must be father nodes b, we do not who tube b)
2.b below a: the number of all ideas tree +1 ~ dep (p) + k a rectangular frame (dep (p) and

So thinking: Chairman of the tree each node to maintain the number of ideas under the same tree and depth; subscript depth, weight maintenance is the number of sub-tree and; the establishment of the President of trees in the dfs sequence in and out the timestamp on the tree the nature of the problem into a sequence of intervals, using dfs timestamp order (in the sub-tree ID and time stamps the timestamp interval), p is a query tree root; the question then transitions to query timestamp interval from the inner and the right point (query number corresponding to the rectangular frame portion of the live point) k a. With seemingly segment tree maintenance it is also possible.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,q;

const int maxn = 3e5+10;
vector<int> g[maxn];
int depth[maxn];
ll size[maxn];
int e = 0;
int in[maxn],out[maxn],root[maxn];
int ma_siz[maxn],ma_dep[maxn];
struct Node{
    ll v;
    int lc,rc;
}T[maxn*24];

//递归计算dfs序 size子树大小 depth深度 
void dfs(int x,int fa){
    in[x] = ++e;
    size[x] = 1;
    depth[x] = depth[fa] + 1;
    for(int i=0;i<g[x].size();i++){
        int v = g[x][i];
        if(v != fa){
            dfs(v,x);
            size[x] += size[v];
        }
    }
    out[x] = e;
}

//主席树update 
void update(int pre,int cur,int pos,ll v,int l,int r){
    if(l == r){
        T[cur].v = T[pre].v + v;
        return;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid){
        T[cur].lc = ++e;
        T[cur].rc = T[pre].rc;
        update(T[pre].lc,T[cur].lc,pos,v,l,mid);
    }else{
        T[cur].rc = ++e;
        T[cur].lc = T[pre].lc;
        update(T[pre].rc,T[cur].rc,pos,v,mid+1,r);
    }
    T[cur].v = T[T[cur].lc].v + T[T[cur].rc].v;
}

//查询区间ql~qr的权值(子树个数和) emmm是不是直接用权值线段树也是可以的啊 
ll query(int pre,int cur,int ql,int qr,int l,int r){
    if(ql <= l && r <= qr){
        return T[cur].v - T[pre].v;
    }
    int mid = (l + r) >> 1;
    ll res = 0;
    if(ql <= mid) res += query(T[pre].lc,T[cur].lc,ql,qr,l,mid);
    if(qr > mid) res += query(T[pre].rc,T[cur].rc,ql,qr,mid+1,r);
    return res;
}

int main(){
    ios::sync_with_stdio(false);
    cin>>n>>q;
    for(int i=1;i<=n-1;i++){
        int u,v;
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1,1);
    for(int i=1;i<=n;i++){
        size[i]--;
        ma_siz[in[i]] = size[i]; //新序号-dfs序上的权值:子树个数 
        ma_dep[in[i]] = depth[i]; //新序号-dfs序上的下标:所在位置为深度dep 
    }
    for(int i=1;i<=n;i++){
        root[i] = ++e;
        update(root[i-1],root[i],ma_dep[i],ma_siz[i],1,n);
    }
    while(q--){
        int p,k;
        cin>>p>>k;
        cout<<(ll)min(depth[p]-1,k)*size[p] + (ll) query(root[in[p]],root[out[p]],depth[p]+1,min(depth[p]+k,n),1,n)<<endl;
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/fisherss/p/12230649.html