专栏文章
P2633 Count on a tree
P2633题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @miqz2sht
- 此快照首次捕获于
- 2025/12/04 13:05 3 个月前
- 此快照最后确认于
- 2025/12/04 13:05 3 个月前
题面
给一棵树,每个点有点权。 次询问 ,求 的路径上所有点的点权中,第 小的那个。
询问强制在线:。
题解
区间第 小可以用主席树加区间前缀和解决。具体而言,如果 的值域内,前 个数有 个,前 个数里有 个,则 内在值域内的数,有 个。
延展到树上,我们每个节点从它的父节点版本拓展出来,构建主席树。于是 版本的权值线段树,代表的就是 到 这条路径上点塞入权值线段树。
类似于区间第 小的差分,我们在树上也可以差分。
求 路径上的第 小,则运用公式: 即可判断是在左区间还是右区间。
CODE:
CPP
#include<bits/stdc++.h>
#define ls(p) tr[p].ls
#define rs(p) tr[p].rs
using namespace std;
const int N=1e5+5;
int n,m,lst,a[N],b[N],c[N],ctp;
int rt[N],tot,g[N][22],dep[N];
vector<int> e[N];
struct NODE{
int ls,rs,sum;
}tr[N*22];
void ins(int v,int &u,int l,int r,int x){
//v 依赖版本,u 新开版本
u=++tot;
tr[u]=tr[v], tr[u].sum=tr[v].sum+1;
if(l==r) return;
int mid=(l+r)>>1;
if(x<=mid) ins(ls(v),ls(u),l,mid,x);
else ins(rs(v),rs(u),mid+1,r,x);
}
int query(int u,int v,int x,int y,int l,int r,int k){
//lca(u,v)=x, y=fa[x], 当前权值范围:[l,r]
if(l==r) return l;
int s=tr[ls(u)].sum+tr[ls(v)].sum-tr[ls(x)].sum-tr[ls(y)].sum;
int mid=(l+r)>>1;
if(k<=s) return query(ls(u),ls(v),ls(x),ls(y),l,mid,k);
return query(rs(u),rs(v),rs(x),rs(y),mid+1,r,k-s);
}
void dfs(int u,int fa){
dep[u]=dep[fa]+1;
g[u][0]=fa;
ins(rt[fa],rt[u],1,ctp,a[u]);
for(int i=1;i<=20;i++){
g[u][i]=g[g[u][i-1]][i-1];
}
for(auto v:e[u]){
if(v==fa) continue;
dfs(v,u);
}
}
int LCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=20;i>=0;i--){
if(dep[g[x][i]]>=dep[y]) x=g[x][i];
}
if(x==y) return x;
for(int i=20;i>=0;i--){
if(g[x][i]!=g[y][i]){
x=g[x][i];
y=g[y][i];
}
}
return g[x][0];
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=a[i];
}
sort(b+1,b+1+n);
for(int i=1;i<=n;i++){
if(i==1 || b[i]!=b[i-1]){
c[++ctp]=b[i];
}
}
for(int i=1;i<=n;i++){
int x=lower_bound(c+1,c+1+ctp,a[i])-c;
a[i]=x;
}
for(int i=1;i<n;i++){
int x,y; cin>>x>>y;
e[x].push_back(y);
e[y].push_back(x);
}
dfs(1,0);
while(m--){
int x,y,k,lca;
cin>>x>>y>>k;
x=(x^lst), lca=LCA(x,y);
lst=c[query(rt[x],rt[y],rt[lca],rt[g[lca][0]],1,ctp,k)];
cout<<lst<<'\n';
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...