[湖南集训]更为厉害 树上主席树-以树深度为下下标建立主席树

Posted 昵称很长很长真是太好了

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[湖南集训]更为厉害 树上主席树-以树深度为下下标建立主席树相关的知识,希望对你有一定的参考价值。

题意题解:
首先对于树上某个点a来说,假设点b是a的祖先(也就是在a的上面),那么答案很好计算,也就是 m i n ( k , d e p [ a ] − 1 ) ∗ ( s i z e [ a ] − 1 ) min(k,dep[a]-1)*(size[a]-1) min(k,dep[a]1)(size[a]1)

麻烦的就是计算b在a下面的情况。
主席树。
如何建立这颗主席树呢?
按照每个结点的深度建立主席树即可。
对于下面的结点来说,我们假设一个结点 i i i,那么这个结点对答案的贡献则为 s i z e [ i ] − 1 size[i]-1 size[i]1
那么我们在dfs序的时候,对于结点 i i i,插入权值为 s i z e [ i ] − 1 size[i]-1 size[i]1即可(size为子树大小)
这样就把他给变成了二维数点的问题了。
也就是查询a这颗子树,深度为 d e p [ a ] + 1 到 d e p [ a ] + k dep[a]+1到dep[a]+k dep[a]+1dep[a]+k的和即可。

代码:

#include<bits/stdc++.h>
#define endl '\\n'
//#define int long long
using namespace std;

const int maxn=3e5+10;

int rt[maxn],ls[maxn*50],rs[maxn*50];
long long sum[maxn*50];
int tot,n,q;
void update(int &node,int start,int ends,int lst,int pos,int val){
    node=++tot;
    ls[node]=ls[lst];
    rs[node]=rs[lst];
    sum[node]=sum[lst]+val;
    if(start==ends) return;
    int mid=(start+ends)/2;
    if(pos<=mid) update(ls[node],start,mid,ls[lst],pos,val);
    else update(rs[node],mid+1,ends,rs[lst],pos,val);
}
long long query(int start,int ends,int l,int r,int x,int y){
    if(l<=start&&ends<=r){
        return sum[y]-sum[x];
    }
    int mid=(start+ends)/2;
    long long ans=0;
    if(l<=mid) ans+=query(start,mid,l,r,ls[x],ls[y]);
    if(mid<r) ans+=query(mid+1,ends,l,r,rs[x],rs[y]);
    return ans;
}

vector<int> edge[maxn];
int siz[maxn],son[maxn],in[maxn],fa[maxn],dep[maxn];
int cnt;
void dfs1(int u,int f){
    dep[u]=dep[f]+1;
    siz[u]=1;
    for(auto i:edge[u]){
        if(i==f) continue;
        dfs1(i,u);
        siz[u]+=siz[i];
    }
}
void build(int u,int f){
    in[u]=++cnt;
    update(rt[cnt],1,n,rt[cnt-1],dep[u],siz[u]-1);
    for(auto i:edge[u]){
        if(i==f) continue;
        build(i,u);
    }
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n>>q;
    for(int i=1;i<n;i++){
        int x,y;
        cin>>x>>y;
        edge[x].push_back(y);
        edge[y].push_back(x);
    }
    dfs1(1,0);
//    dfs2(1,1);
    build(1,0);
    while(q--){
        int x,y;
        cin>>x>>y;
        long long ans=min(y,dep[x]-1)*1ll*(siz[x]-1);
        //cout<<"debug "<<ans<<endl;
        ans+=query(1,n,dep[x]+1,min(dep[x]+y,n),rt[in[x]-1],rt[in[x]+siz[x]-1]);
        cout<<ans<<endl;
        //cout<<"debug "<<maxdep<<" "<<dep[x]+1<<" "<<dep[x]+y<<" "<<in[x]-1<<" "<<in[x]+siz[x]-1<<endl;
    }

}

以上是关于[湖南集训]更为厉害 树上主席树-以树深度为下下标建立主席树的主要内容,如果未能解决你的问题,请参考以下文章

[湖南集训]更为厉害 树上主席树-以树深度为下下标建立主席树

[湖南集训]更为厉害 树上主席树-以树深度为下下标建立主席树

洛谷 - P3899 [湖南集训]谈笑风生(dfs序+主席树/二维数点)

[湖南集训] 谈笑风生 (主席树)

[湖南集训]谈笑风生

题解 P3899 [湖南集训]谈笑风生