[湖南集训]更为厉害 树上主席树-以树深度为下下标建立主席树
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]+1到dep[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;
}
}
以上是关于[湖南集训]更为厉害 树上主席树-以树深度为下下标建立主席树的主要内容,如果未能解决你的问题,请参考以下文章
[湖南集训]更为厉害 树上主席树-以树深度为下下标建立主席树
[湖南集训]更为厉害 树上主席树-以树深度为下下标建立主席树