简化题意
m次询问,每次询问x的子树中,与x节点距离不超过y的节点的子树和。n,m≤300,000。
思路
按照dfs序排序,每次将一个点的答案塞到第depu的位置,这样得到一个前缀和,每次询问作减法即可。
可持久化线段树。
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=3E5+5; 4 typedef long long int ll; 5 ll n,m,x,y,sum[maxn],dep[maxn],cur,t[maxn*20],root[maxn*20],fa[maxn],size,gg; 6 ll ls[maxn*20],rs[maxn*20],ti,dfn[maxn],last[maxn],maxx[maxn],head[maxn*2]; 7 struct edge{ll to,next;}E[maxn*2]; 8 void insert(ll l,ll r,ll pos,ll&num,ll pre,ll val) 9 { 10 num=++cur; 11 t[num]=t[pre]; 12 ls[num]=ls[pre]; 13 rs[num]=rs[pre]; 14 t[num]+=val; 15 if(l==r)return; 16 ll mid=(l+r)>>1; 17 if(pos<=mid)insert(l,mid,pos,ls[num],ls[pre],val); 18 else insert(mid+1,r,pos,rs[num],rs[pre],val); 19 } 20 ll ask(ll L,ll R,ll l,ll r,ll num) 21 { 22 if(L<=l&&r<=R)return t[num]; 23 else if(r<L||R<l)return 0; 24 ll mid=(l+r)>>1; 25 return ask(L,R,l,mid,ls[num])+ask(L,R,mid+1,r,rs[num]); 26 } 27 void add(ll u,ll v) 28 { 29 E[++size].to=v; 30 E[size].next=head[u]; 31 head[u]=size; 32 } 33 void dfs(ll u,ll F,ll d) 34 { 35 dep[u]=d; 36 fa[u]=F; 37 sum[u]=1; 38 maxx[u]=dfn[u]=++ti; 39 last[u]=u; 40 for(ll i=head[u];i;i=E[i].next) 41 { 42 ll v=E[i].to; 43 if(v==F)continue; 44 dfs(v,u,d+1); 45 sum[u]+=sum[v]; 46 if(maxx[v]>maxx[u]) 47 { 48 maxx[u]=maxx[v]; 49 last[u]=last[v]; 50 } 51 } 52 } 53 void init(ll u,ll F,ll d) 54 { 55 insert(1,n,d,root[u],root[gg],sum[u]-1); 56 gg=u; 57 for(ll i=head[u];i;i=E[i].next) 58 { 59 ll v=E[i].to; 60 if(v==F)continue; 61 init(v,u,d+1); 62 } 63 } 64 int main() 65 { 66 // freopen("laugh.in","r",stdin); 67 // freopen("laugh.out","w",stdout); 68 ios::sync_with_stdio(false); 69 cin>>n>>m; 70 for(ll i=1;i<=n-1;++i) 71 { 72 cin>>x>>y; 73 add(x,y); 74 add(y,x); 75 } 76 dfs(1,1,1); 77 gg=1; 78 init(1,1,1); 79 for(ll i=1;i<=m;++i) 80 { 81 cin>>x>>y; 82 if(x==1)cout<<ask(2,1+y,1,n,root[last[1]])<<endl; 83 else cout<<(sum[x]-1)*min(dep[x]-1,y)+ 84 ask(dep[x]+1,dep[x]+y,1,n,root[last[x]])-ask(dep[x]+1,dep[x]+y,1,n,root[x])<<endl; 85 } 86 return 0; 87 }