[湖南集训] 谈笑风生

Description:

设 T 为一棵有根树,我们做如下的定义:

• 设 a 和 b 为 T 中的两个不同节点。如果 a 是 b 的祖先,那么称“a 比 b 不知道高明到哪里去了”。

• 设 a 和 b 为 T 中的两个不同节点。如果 a 与 b 在树上的距离不超过某个给定常数 x,那么称“a 与 b 谈笑风生”。

给定一棵 n 个节点的有根树 T,节点的编号为 1 ∼ n,根节点为 1 号节点。你需要回答 q 个询问,询问给定两个整数 p 和 k,问有多少个有序三元组 (a; b; c) 满足:

1.a、 b 和 c 为 T 中三个不同的点,且 a 为 p 号节点;

2.a 和 b 都比 c 不知道高明到哪里去了;

3.a 和 b 谈笑风生。这里谈笑风生中的常数为给定的 k。

Hint:

$ n,m \le 3*10^5$

Solution:

显然如果b在a上面可以直接算

考虑在a子树中的情况

由于要求的答案是一个深度连续的区间,考虑以深度为下标建主席树

将每个点的贡献size[i]-1依次插入主席树

直接查一个点子树就可以了

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll mxn=3e5+5,mxm=2e7+5;
ll n,m,df,tot,cnt,hd[mxn];
ll in[mxn],sz[mxn],rk[mxn],dep[mxn],dfn[mxn];
ll rt[mxm],s[mxm],ls[mxm],rs[mxm];
ll q[mxm];

inline ll read() {
	char c=getchar(); ll x=0,f=1;
	while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
	while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
	return x*f;
}
inline void chkmax(ll &x,ll y) {if(x<y) x=y;}
inline void chkmin(ll &x,ll y) {if(x>y) x=y;}

struct ed {
	ll to,nxt;
}t[mxn<<1];

inline void add(ll u,ll v) {
	t[++cnt]=(ed) {v,hd[u]}; hd[u]=cnt;
}

ll flag[mxn],lv[mxn];

void dfs(ll u,ll fa) {
	sz[u]=1;  
	dfn[u]=++df; rk[df]=u; dep[u]=dep[fa]+1;
	for(ll i=hd[u];i;i=t[i].nxt) {
		ll v=t[i].to;
		if(v==fa) continue ;
		dfs(v,u); sz[u]+=sz[v]; lv[u]+=lv[v];
	}
}

void update(ll las,ll &p,ll l,ll r,ll pos,ll val) {
	if(!p) p=++tot; s[p]=s[las]+val; 
	if(l==r) return ; ll mid=(l+r)>>1;
	if(pos<=mid) update(ls[las],ls[p],l,mid,pos,val),rs[p]=rs[las];
	else update(rs[las],rs[p],mid+1,r,pos,val),ls[p]=ls[las];
}

ll query(ll las,ll p,ll l,ll r,ll ql,ll qr) {
	if(ql<=l&&r<=qr) return s[p]-s[las];
	ll mid=(l+r)>>1; ll res=0;
	if(ql<=mid) res+=query(ls[las],ls[p],l,mid,ql,qr);
	if(qr>mid) res+=query(rs[las],rs[p],mid+1,r,ql,qr);
	return res;
}

int main()
{
	n=read(); m=read(); ll u,v,k,p;
	for(ll i=1;i<n;++i) {
		u=read(); v=read();
		add(u,v); add(v,u);
		++in[u],++in[v];
	}
	dfs(1,0); 
	for(ll i=1;i<=n;++i) update(rt[i-1],rt[i],1,n,dep[rk[i]],sz[rk[i]]-1);
	for(ll i=1;i<=m;++i) {
		p=read(); k=read();
		printf("%lld\n",query(rt[dfn[p]],rt[dfn[p]+sz[p]-1],1,n,dep[p]+1,dep[p]+k)+(sz[p]-1)*min(k,dep[p]-1));
	}
    return 0;
}

posted @ 2019-03-22 16:28  cloud_9  阅读(162)  评论(0)    收藏  举报