链接:A-智乃酱的子树查询类问题_牛客竞赛数据结构专题班dsu on tree、长链剖分习题 (nowcoder.com)
题意:给定一棵树,有点权,以 1 为根。多次询问,每次询问点 x 的子树内距离 x 的距离在 [ l , r ] [l,r] [l,r] 内的所有点的权值最小值,最大值,权值和。
题解:启发式合并无法删点之后动态快速更新最值,因此采用线段树合并来做。先将所有询问离线,当访问到该点时才计算答案。这样从根搜索出去后,每次将子节点的树合并到父节点上,只会有加点操作,因此可以动态的维护最值,权值和。每个节点下开的是一棵动态开点的权值线段树,权值就是距离 1 节点的距离,这样对于 x 距离 [ l , r ] [l,r] [l,r] 的点即为在 [ d e p [ x ] + l , d e p [ x ] + r ] [dep[x]+l,dep[x]+r] [dep[x]+l,dep[x]+r] 线段树权值范围内的点。
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using ll=long long;
using P=pair<int,int>;
const int inf=1e9;
struct Merge{
static const int N=1e5+5;
int n,now;
vector<int>rt,ls,rs,mx,mn;
vector<ll>sm;
Merge(int x=N):n((x+5)*50),now(0),rt(x+5),ls(n),rs(n),sm(n),mx(n),mn(n,inf){}
void pushup(int k){
int l=ls[k],r=rs[k];
sm[k]=sm[l]+sm[r];
mx[k]=max(mx[l],mx[r]);
mn[k]=min(mn[l],mn[r]);
}
void update(int&u,int l,int r,int pos,int w){
if(!u)u=++now;
if(l==r)
{
sm[u]+=w;
mx[u]=max(mx[u],w);
mn[u]=min(mn[u],w);
return;
}
int mid=l+r>>1;
if(pos<=mid)update(ls[u],l,mid,pos,w);
else update(rs[u],mid+1,r,pos,w);
pushup(u);
}
void merge(int&u,int&v,int l,int r){
if(!u||!v){u=u|v; return;}
if(l==r)
{
mx[u]=max(mx[u],mx[v]);
mn[u]=min(mn[u],mn[v]);
sm[u]+=sm[v];
return;
}
int mid=l+r>>1;
merge(ls[u],ls[v],l,mid);
merge(rs[u],rs[v],mid+1,r);
pushup(u);
}
ll sum,mxx,mnn;
void query(int u,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)
{
sum+=sm[u];
mxx=max(mxx,(ll)mx[u]);
mnn=min(mnn,(ll)mn[u]);
return;
}
int mid=l+r>>1;
if(ql<=mid)query(ls[u],l,mid,ql,qr);
if(mid<qr)query(rs[u],mid+1,r,ql,qr);
}
};
void solve()
{
int n; cin>>n;
vector<int>a(n+1);
vector<vector<int>>ed(n+1);
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1,u,v;i<n;i++)
{
cin>>u>>v;
ed[u].push_back(v);
ed[v].push_back(u);
}
int m; cin>>m;
struct node{
int l,r,id;
};
vector<vector<node>>q(n+1);
vector<array<ll,3>>ans(m+1);
for(int i=1,u,v,w;i<=m;i++)
{
cin>>u>>v>>w;
q[u].push_back({v,w,i});
}
Merge tr(n);
vector<int>dep(n+1);
auto dfs=[&](auto dfs,int x,int fa)->void{
dep[x]=dep[fa]+1;
tr.update(tr.rt[x],1,n,dep[x],a[x]);
for(auto y:ed[x])
{
if(y==fa)continue;
dfs(dfs,y,x);
tr.merge(tr.rt[x],tr.rt[y],1,n);
}
for(auto[l,r,id]:q[x])
{
tr.sum=tr.mxx=0,tr.mnn=1e9;
tr.query(tr.rt[x],1,n,dep[x]+l,dep[x]+r);
ans[id]={tr.mnn,tr.mxx,tr.sum};
}
};
dfs(dfs,1,0);
for(int i=1;i<=m;i++)
{
auto[mn,mx,sm]=ans[i];
cout<<mn<<" "<<mx<<" "<<sm<<"\n";
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int t=1; //cin>>t;
while(t--)solve();
return 0;
}