首先根据题目给的条件,发现\(a,b\)都要是\(c\)的父亲。
因此这三个点是树上的一条深度单增的链。
由于\(a,b\)之间距离不超过\(k\),而且\(a\)被钦定了,因此只有两种状况:
一种是\(a\)是\(b\)的祖先,贡献是\(\sum_b size[b]-1\),也就是全部\(b\)能够选择的点的子树和。
另一种\(b\)是\(a\)的祖先,贡献是\(\sum_b size[a]-1\),钦定一个\(b\)以后,\(c\)能够在\(a\)的子树中任选。
第二种状况很简单,由于\(size[a]\)是定值,而且每一个点的父亲是惟一的,因此第二部分很容易算。
困难的是第一部分,然而依旧不难把。。。
方法不少,好比说,你把\(dfs\)序和深度当作\(x,y\)轴,这样子就是二维数点,直接主席树。
或者说直接点分治也能够。ios
固然,既然想写长链剖分,那就固然要用长链剖分来作啊。
咱们发现,全部的值都由重儿子向后挪动一位得来,而咱们要求的东西须要维护一个区间和。
这样子很很差用前缀和来作,因此咱们能够用一个后缀和啊!
这样子就很舒服了,直接维护后缀和,而后长链剖分转移,能够作到复杂度\(O(n)\)。spa
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<vector> using namespace std; #define ll long long #define MAX 300300 inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } struct Ask{int id,k;}; vector<Ask> p[MAX]; struct Line{int v,next;}e[MAX<<1]; int h[MAX],cnt=1; inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;} ll tmp[MAX],*s[MAX],*id=tmp,ans[MAX]; int md[MAX],dep[MAX],fa[MAX],hson[MAX],size[MAX]; void dfs1(int u,int ff) { md[u]=dep[u]=dep[ff]+1;fa[u]=ff;size[u]=1; for(int i=h[u];i;i=e[i].next) { int v=e[i].v;if(v==ff)continue; dfs1(v,u);size[u]+=size[v]; if(md[v]>md[hson[u]])hson[u]=v; } if(hson[u])md[u]=md[hson[u]]; } void dfs(int u) { s[u][0]=size[u]-1; if(hson[u])s[hson[u]]=s[u]+1,dfs(hson[u]),s[u][0]+=s[hson[u]][0]; for(int i=h[u];i;i=e[i].next) { int v=e[i].v;if(v==fa[u]||v==hson[u])continue; s[v]=id;id+=md[v]-dep[v]+1;dfs(v); for(int j=0;j<=md[v]-dep[v];++j)s[u][j+1]+=s[v][j]; s[u][0]+=s[v][0]; } for(int i=p[u].size()-1;~i;--i) { int k=p[u][i].k,id=p[u][i].id; ans[id]+=1ll*(size[u]-1)*min(dep[u]-1,k); if(k>=md[u]-dep[u])ans[id]+=s[u][0]-size[u]+1; else ans[id]+=s[u][0]-size[u]+1-s[u][k+1]; } } int n,Q; int main() { n=read();Q=read(); for(int i=1;i<n;++i) { int u=read(),v=read(); Add(u,v);Add(v,u); } dfs1(1,0); for(int i=1;i<=Q;++i) { int u=read(),k=read(); p[u].push_back((Ask){i,k}); } s[1]=id;id+=md[1];dfs(1); for(int i=1;i<=Q;++i)printf("%lld\n",ans[i]); return 0; }