点分树模板
- 建立新树,存储信息,强制在线询问
cpp
int n,m,A;
vector<PII> adj[N];
bool st[N];
int age[N];
struct Father{
int u,num,dis;
};
vector<Father> f[N];//所有父亲信息,最多有logn个父亲
struct Son{
int age,dis;
bool operator<(const Son&tmp)const{
return age<tmp.age;
}
};
vector<Son> son[N][3];//所有儿子信息
int get_size(int u,int fa){
if(st[u])return 0;
int res=1;
for(auto [v,w]:adj[u]){
if(v==fa)continue;
res+=get_size(v,u);
}
return res;
}
int get_wc(int u,int fa,int tot,int &wc){
if(st[u])return 0;
int sum=1,ms=0;
for(auto [v,w]:adj[u]){
if(v==fa)continue;
int t=get_wc(v,u,tot,wc);
ms=max(ms,t);
sum+=t;
}
ms=max(ms,tot-sum);
if(ms<=tot/2)wc=u;
return sum;
}
void get_dis(int u,int fa,int dis,int wc,int k,vector<Son>&p){
if(st[u])return;
f[u].push_back({wc,k,dis});
p.push_back({age[u],dis});
for(auto [v,w]:adj[u]){
if(v==fa)continue;
get_dis(v,u,dis+w,wc,k,p);
}
}
void cal(int u){
if(st[u])return;
get_wc(u,0,get_size(u,0),u);
st[u]=true;
int k=0;
for(auto [v,w]:adj[u]){
if(st[v])continue;
auto &p=son[u][k];
p.push_back({-1,0}),p.push_back({A+1,0});//哨兵
get_dis(v,0,w,u,k,p);
k++;
sort(p.begin(),p.end());
for(int i=1;i<p.size();i++)p[i].dis+=p[i-1].dis;
}
for(auto [v,w]:adj[u])cal(v);
}
int query(int u,int l,int r){
int res=0;
for(auto &[fa,num,dis]:f[u]){
int g=age[fa];
if(g>=l&&g<=r)res+=dis;
for(int i=0;i<3;i++){
if(i==num)continue;
auto &p=son[fa][i];
if(p.empty())continue;
int L=lower_bound(p.begin(),p.end(),Son{l,-1})-p.begin();
int R=lower_bound(p.begin(),p.end(),Son{r+1,-1})-p.begin();
res+=dis*(R-L)+p[R-1].dis-p[L-1].dis;
}
}
for(int i=0;i<3;i++){
auto &p=son[u][i];
if(p.empty())continue;
int L=lower_bound(p.begin(),p.end(),Son{l,-1})-p.begin();
int R=lower_bound(p.begin(),p.end(),Son{r+1,-1})-p.begin();
res+=p[R-1].dis-p[L-1].dis;
}
return res;
}
void solve(){
cin>>n>>m>>A;
for(int i=1;i<=n;i++)cin>>age[i];
for(int i=1;i<n;i++){
int u,v,w;
cin>>u>>v>>w;
adj[u].push_back({v,w});
adj[v].push_back({u,w});
}
cal(1);
int res=0;
while(m--){
int u,a,b;
cin>>u>>a>>b;
int l=(a+res)%A,r=(b+res)%A;
if(l>r)swap(l,r);
//询问树上年龄在[l,r]的点到u的距离之和
res=query(u,l,r);
cout<<res<<"\n";
}
}