题意太长 不赘述
考虑如何去求三元组(a,b,c)
1.b是a的祖先 这个很好算 因为a的每个儿子都可以作为c 然后b和a的距离不超过k就行 显然就是
2.a是b的祖先 这个才是这题的难度所在
设tid[x]为x的dfs序
如果a是b的祖先
并且 依题意
这就变成了一个二维数点的模型 以tid为x轴 dep为y轴 那不就是在矩形 (tid[a],dep[a]), (tid[a]+siz[a]-1,dep[a]+k)里面有多少个点吗 对于每个合法的b点 对答案的贡献显然是
用树状数组维护就行了 如果想在线搞得话 主席树就行
扫描二维码关注公众号,回复:
11392729 查看本文章
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5+100;
typedef long long ll;
int h[N],nex[N<<1],to[N<<1],cur;
int n,q,dep[N],siz[N],tid[N],dfn,tot;
ll c[N],res[N];
void add(int x,ll val){
while(x<=n){
c[x]+=val;
x+=x&-x;
}
}
ll query(int x){
ll ret=0;
while(x){
ret+=c[x];
x-=x&-x;
}
return ret;
}
void add_edge(int x,int y){
to[++cur]=y;nex[cur]=h[x];h[x]=cur;
}
void dfs(int u,int fa){
siz[u]=1;dep[u]=dep[fa]+1;tid[u]=++dfn;
for(int i = h[u]; i; i = nex[i]){
int v = to[i];
if(v==fa) continue;
dfs(v,u);
siz[u]+=siz[v];
}
}
struct node{
int sz,de,ti;
bool operator <(const node& a)const{
return de<a.de;
}
}T[N];
struct line{
int l,r,h,id,op;
bool operator < (const line& a)const{
return h<a.h;
}
}p[N<<1];
int main(){
scanf("%d%d",&n,&q);
for(int i = 1; i <= n-1; i++){
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v);add_edge(v,u);
}
dfs(1,0);
for(int i = 1; i <= n; i++) T[i]=(node){siz[i]-1,dep[i],tid[i]};
for(int i = 1; i <= q; i++){
int x,y;
scanf("%d%d",&x,&y);
p[++tot]={tid[x],tid[x]+siz[x]-1,dep[x],i,-1};
p[++tot]={tid[x],tid[x]+siz[x]-1,dep[x]+y,i,1};
res[i]+=1ll*(siz[x]-1)*min(dep[x]-1,y);
}
sort(p+1,p+1+tot);
sort(T+1,T+1+n);
for(int i = 1,j = 1; i <= tot; i++){
while(j<=n&&T[j].de<=p[i].h) add(T[j].ti,T[j].sz),j++;
res[p[i].id]+=1ll*p[i].op*(query(p[i].r)-query(p[i].l));
}
for(int i = 1; i <= q; i++) printf("%lld\n",res[i]);
return 0;
}