P3899 [湖南集訓]談笑風生 - 線段樹合併
阿新 • • 發佈:2021-06-28
題解
對於每個點,以深度為下標記錄答案。
如果線段樹合併想線上,Merge
函式需要這樣寫:
int Merge(int p,int q){
if(!p||!q) return p^q;
int res=Newnode(t[p].l,t[p].r,t[p].v+t[q].v);
ls(res)=Merge(ls(p),ls(q)),rs(res)=Merge(rs(p),rs(q));
return res;
}
當 \(p\) 或 \(q\) 為空時,直接返回另一個。這保證了線段樹合併的時空複雜度,但也使得修改父親節點的線段樹時可能修改到子節點。
兩種解決方案:
- 將修改放到合併前面;
- 將修改可持久化。這樣,每次修改一定不會影響原樹。合併時只合並最後一個版本即可。
程式碼
#include <cstdio> #include <cstring> #include <cctype> #include <vector> using namespace std; #define For(Ti,Ta,Tb) for(int Ti=(Ta);Ti<=(Tb);++Ti) #define Dec(Ti,Ta,Tb) for(int Ti=(Ta);Ti>=(Tb);--Ti) template<typename T> void Read(T &x){ x=0;int _f=1; char ch=getchar(); while(!isdigit(ch)) _f=(ch=='-'?-1:_f),ch=getchar(); while(isdigit(ch)) x=x*10+(ch^48),ch=getchar(); x=x*_f; } template<typename T,typename... Args> void Read(T &x,Args& ...others){ Read(x);Read(others...); } typedef long long ll; const int Inf=0x3f3f3f3f,N=3e5+5; int n,q; vector<int> G[N]; int dep[N],siz[N]; void Dfs(int u,int fa){ dep[u]=dep[fa]+1,siz[u]=1; for(int v:G[u]){ if(v==fa) continue; Dfs(v,u);siz[u]+=siz[v]; } } #define ls(xx) t[xx].ls #define rs(xx) t[xx].rs struct Node{ int l,r,ls,rs;ll v; }t[20000000]; int tot=0; int Newnode(int l,int r,ll v=0){ t[++tot]=Node{l,r,0,0,v}; return tot; } void Pushup(int p){t[p].v=t[ls(p)].v+t[rs(p)].v;} void Add(int p,int pos,ll x){ if(t[p].l==t[p].r){ t[p].v+=x;return; } int mid=(t[p].l+t[p].r)>>1; if(pos<=mid){ if(!ls(p)) ls(p)=Newnode(t[p].l,mid); Add(ls(p),pos,x); }else{ if(!rs(p)) rs(p)=Newnode(mid+1,t[p].r); Add(rs(p),pos,x); } Pushup(p); } ll Query(int p,int l,int r){ if(!p||r<t[p].l||l>t[p].r) return 0; if(l<=t[p].l&&t[p].r<=r) return t[p].v; return Query(ls(p),l,r)+Query(rs(p),l,r); } int Merge(int p,int q){ if(!p||!q) return p^q; int res=Newnode(t[p].l,t[p].r,t[p].v+t[q].v); ls(res)=Merge(ls(p),ls(q)),rs(res)=Merge(rs(p),rs(q)); return res; } int root[N]; void Work(int u,int fa){ root[u]=Newnode(1,n); Add(root[u],dep[u],siz[u]-1); for(int v:G[u]){ if(v==fa) continue; Work(v,u); root[u]=Merge(root[u],root[v]); } } int main(){ Read(n,q); int u,v; For(i,1,n-1){ Read(u,v); G[u].push_back(v),G[v].push_back(u); } Dfs(1,0); Work(1,0); while(q--){ int p,k;Read(p,k); printf("%lld\n",1LL*min(dep[p]-1,k)*(siz[p]-1)+Query(root[p],dep[p]+1,min(dep[p]+k,n))); } return 0; }