#include<iostream> #include<string.h> #include<algorithm> #include<stdio.h> #include<math.h> #define rep(i,j,k) for(int i=j;i<=k;i++) #define per(i,j,k) for(int i=j;i>=k;i--) #define LL long long using namespace std; const int maxx = 3e5+6; struct node{ int l,r; LL val; }tree[maxx<<5]; int ver[maxx*2],Next[maxx*2],head[maxx]; ///邻接表 int deapth[maxx],Size[maxx],dfn[maxx],root[maxx]; ///深度数组 包含自己在内的子节点数目 DFS序 主席树的根 int tot,order,deep,cnt; ///边的序号 DFS序标记 最深深度 void add(int x,int y){ ver[++tot]=y;Next[tot]=head[x];head[x]=tot; ver[++tot]=x;Next[tot]=head[y];head[y]=tot; } void inserts(int l,int r,int pre,int &now,int pos,LL val){ ///动态开点部分 now=++cnt; ///把旧的节点的信息更新到新的节点上 tree[now]=tree[pre]; ///维护前缀和 tree[now].val+=val; if (l==r){ return; } int mid=(l+r)>>1; if (pos<=mid){ inserts(l,mid,tree[pre].l,tree[now].l,pos,val); }else { inserts(mid+1,r,tree[pre].r,tree[now].r,pos,val); } } LL query(int L,int R,int l,int r,int ql,int qr){ LL ans=0; ///如果在范围内,直接返回 if (ql<=l && r<=qr){ return tree[R].val-tree[L].val; } int mid=(l+r)>>1; if(ql<=mid)ans+=query(tree[L].l,tree[R].l,l,mid,ql,qr); if(qr>mid)ans+=query(tree[L].r,tree[R].r,mid+1,r,ql,qr); return ans; } void dfs1(int x,int fa){ Size[x]=1; deapth[x]=deapth[fa]+1; ///更新最深是深度 deep=max(deep,deapth[x]); for(int i=head[x];i;i=Next[i]){ if(ver[i]==fa)continue; dfs1(ver[i],x); Size[x]+=Size[ver[i]]; } } void dfs2(int x,int fa){ dfn[x]+=++order; ///这里注意,由于我们需要按照树的变量顺序来建立序列,所以应该是root[order-1],root[order] ///size减1是为了减去自己 inserts(1,deep,root[order-1],root[order],deapth[x],Size[x]-1); for (int i=head[x];i;i=Next[i]){ if(ver[i]==fa)continue; dfs2(ver[i],x); } } int main(){ int n,q; int uu,vv,l,r; while(~scanf("%d%d",&n,&q)){ order=0; deep=0; cnt=0; memset(Next,0,sizeof(Next)); memset(Size,0,sizeof(Size)); memset(dfn,0,sizeof(dfn)); memset(deapth,0,sizeof(deapth)); rep(i,1,n-1){ scanf("%d%d",&uu,&vv); add(uu,vv); } dfs1(1,0); dfs2(1,0); LL ans=0; int p,k; while(q--){ scanf("%d%d",&p,&k); ans=0; ///当a点在b点的的下面,那么b所处于的位置,应该是其a的深度和k当中小的那个 ///因为b只会在a的上面k个位置,并且如果a的深度太小的话,其深度可能达不到k个 ///C的位置的可能一定是a的子节点 ans+=(LL)(Size[p]-1)*min(k,deapth[p]-1); ///当b点在a的下端,那么c应该在b的子节点中 ///所以我们要查询a也就是p的子节点中 所以第一个范围oot[dfn[p]-1],root[dfn[p]+Size[p]-1] ///查询其子节点中深度在deepth[p]+1到death[p]+k的节点中子节点的个数和 ///因为我们构架线段树的时候,构建的是前缀和 ans+=query(root[dfn[p]-1],root[dfn[p]+Size[p]-1],1,deep,deapth[p]+1,min(deapth[p]+k,deep)); if (deapth[p]==deep)ans=0; printf("%lld ",ans); } } return 0; }