[湖南集训] 谈笑风生
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;
}