可在线版题解
既然有离线的树状数组版本(时间空间非常优秀)题解,那怎么少的了可在线的主席树版本呢(时间空间不是很优秀)。
前置芝士
序,离散化,主席树
思路
1.像这种对某个子树进行查询的操作,并且多组查询,很明显需要将整棵树拍扁(就是求 序),这样我们就可以将子树化为一个连续的区间进行维护。
2.题目要求子树内距离该子树的根 的距离大于 的距离和,我们可以先求出所有点到根 的距离,这样一棵子树内某个点 距离该子树根 的距离就一目了然了,就是。然后我们求出子树内满足 即可。但是这每次询问枚举一整棵子树复杂度高达 ,非常不合理,我们需要维护子树。
3.其实也很明显,维护一个子树内的每个离根的不同距离 的前缀和,最大值可能高达,我们需要离散化距离,不过得记住确切距离是多少(毕竟离散化距离后最多只有 种,同时记住每个位置的真实距离,那么题目所求便是某个区间(代表某棵子树)的大于某个值的后缀距离和,还没求完,才求一半)。
4.那主席树维护除了维护刚才提到的后缀距离和,还要维护后缀点数和,因为答案是
所以查询时返回二元组即可。
#include<iostream> #include<algorithm> #include<vector> using namespace std; typedef long long ll; typedef pair<ll,ll> P; const int maxn=2e5+5; ll ds[maxn],pos[maxn],k; ll lc[maxn<<5],rc[maxn<<5],sum[maxn<<5],ti[maxn<<5],rt[maxn],now;//sum是距离和,ti是点数和。 ll n,q,x,u,v,w,cnt,p; struct node{ ll id,st,en,dis; inline bool operator<(const node&x)const{ return st<x.st; } }dfn[maxn]; vector<P>ed[maxn]; void dfs(int x,int fa,ll d) { dfn[x].id=x; dfn[x].st=dfn[x].en=++cnt; dfn[x].dis=ds[x]=d; for(auto y:ed[x]) { if(y.first==fa)continue; dfs(y.first,x,d+y.second); dfn[x].en=max(dfn[x].en,dfn[y.first].en); } return; } void build(ll&t,int l,int r) { t=++now; if(l==r)return; int mid=l+r>>1; build(lc[t],l,mid); build(rc[t],mid+1,r); return; } int update(int o,int l,int r,int x,ll y) { int t=++now; lc[t]=lc[o]; rc[t]=rc[o]; sum[t]=sum[o]+y; ti[t]=ti[o]+1; if(l==r)return t; int mid=l+r>>1; if(x<=mid)lc[t]=update(lc[o],l,mid,x,y); else rc[t]=update(rc[o],mid+1,r,x,y); return t; } P query(int u,int v,int l,int r,int x) { if(l==r)return P(sum[v]-sum[u],ti[v]-ti[u]); int mid=l+r>>1; P res; if(x<=mid)//小于等于中点的右区间全加上即可 { res=query(lc[u],lc[v],l,mid,x); res.first+=sum[rc[v]]-sum[rc[u]]; res.second+=ti[rc[v]]-ti[rc[u]]; } else res=query(rc[u],rc[v],mid+1,r,x); return res; } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n; for(int i=2;i<=n;i++) { cin>>u>>v; ed[u].push_back(P(i,v)); ed[i].push_back(P(u,v)); } dfs(1,0,0); sort(ds+1,ds+1+n); sort(dfn+1,dfn+1+n); p=unique(ds+1,ds+1+n)-ds-1; build(rt[0],1,p); for(int i=1;i<=n;i++) { pos[dfn[i].id]=i; dfn[i].dis=lower_bound(ds+1,ds+1+p,dfn[i].dis)-ds; rt[i]=update(rt[i-1],1,p,dfn[i].dis,ds[dfn[i].dis]); } cin>>q; for(int i=1;i<=q;i++) { cin>>u>>v; w=pos[u]; int l=dfn[w].st,r=dfn[w].en; ll dd=ds[dfn[w].dis]+v; int pp=lower_bound(ds+1,ds+1+p,dd)-ds; if(pp>p)cout<<0<<"\n"; else { P ans=query(rt[l-1],rt[r],1,p,pp); cout<<ans.first-ans.second*ds[dfn[w].dis]<<"\n"; } } return 0; }