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

P3899 [湖南集训]谈笑风生

solve

通过观察我们发现,a是固定不动的,而b距离a不超过k

则b有两种情况。

((i))b在a的上方

(b)(a)的距离最大为$ min(deep[a],k)$

(c)就是(a)子树的任意一点。

则对答案的贡献就是$ min(deep[a],k)* (size[a]-1) $

((ii))b是a的下方

那我们b是a子树上距离(a)不超过k也就是深度差不超过k的一个点

(c)就是(b)子树上的一个点

对答案的贡献就是把所有可能的(size[b])加起来

我们以(deep[x])为下标,(size[x])为权值建主席树,就可以统计出(sum)总和了。

注意一点,数据比较大,要开long long

code

#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
const int maxn=600005;
typedef long long LL;
int N,Q,son[maxn],nxt[maxn],lnk[maxn],cnt,deep[maxn],size[maxn],r[maxn],tot,q[maxn],l[maxn],sz,root[maxn];
struct data{
	int l,r;
	LL sum;
}tr[maxn*32];
inline int read(){
	int ret=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
	while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
	return ret*f;
}
int add_e(int x,int y){son[++cnt]=y;nxt[cnt]=lnk[x];lnk[x]=cnt;}
void dfs(int u,int fa){
	l[u]=++tot;deep[u]=deep[fa]+1;q[tot]=u;size[u]=1;
	for(int j=lnk[u];j;j=nxt[j]){
		if(son[j]==fa)continue;
		dfs(son[j],u);size[u]+=size[son[j]];
	}
	r[u]=tot;
}
void insert(int &x,int l,int r,int pos,int val){
	tr[++sz]=tr[x];x=sz;
	tr[x].sum+=(LL)val;
	if(l==r)return ;
	int mid=(l+r)>>1;
	if(pos<=mid)insert(tr[x].l,l,mid,pos,val);
	else insert(tr[x].r,mid+1,r,pos,val);
}
void update(int x){
	int l=tr[x].l,r=tr[x].r;
	tr[x].sum=tr[l].sum+tr[r].sum;
}
LL query(int i,int j,int l,int r,int ll,int rr){
	if(ll<=l&&r<=rr)return tr[j].sum-tr[i].sum;
	int mid=(l+r)>>1;
	LL ans=0;
	if (ll<=mid)ans+=query(tr[i].l,tr[j].l,l,mid,ll,rr);
	if (rr>mid)ans+=query(tr[i].r,tr[j].r,mid+1,r,ll,rr);
	return ans;
} 
int main(){
	freopen("3653.in","r",stdin);
	freopen("3653.out","w",stdout);
	N=read();Q=read();
	for(int i=1;i<N;i++){
		int x=read(),y=read();
		add_e(x,y);add_e(y,x);
	}
	dfs(1,0);
	for(int i=1;i<=N;i++)root[i]=root[i-1],insert(root[i],1,N,deep[q[i]],size[q[i]]-1);
	for(int i=1;i<=Q;i++){
		int x=read(),k=read();
		LL t=query(root[l[x]],root[r[x]],1,N,deep[x]+1,deep[x]+k);
		int len=min(k,deep[x]-1);
		printf("%lld
",t+(LL)len*(LL)(size[x]-1));
	}
	return 0;
}
原文地址:https://www.cnblogs.com/martian148/p/13305833.html