P2633 Count on a tree
P2633 Count on a tree
静态第 \(k\) 小,想到主席树。
但是主席树大多数情况下是序列问题,这道题在树上。
想一想之前写过的第 \(k\) 小板子,发现主席树是具有前缀性质的。
于是在这道题中,考虑将原本主席树中:第 \(i\) 棵线段树维护前 \(i\) 个数的出现次数 改为 第 \(i\) 棵线段树表示结点 \(i\) 到根的路径中数的出现次数
然后根据这个维护前缀的定义,取出 \(u->v\) 路径上这一段数时,将路径分为 \(3\) 部分
- \(u->LCA\)下面一层,这就是 \(sum(u)-sum(LCA)\)
- \(v-> LCA\)下面一层,就是 \(sum(v)-sum(LCA)\)
- \(LCA\) 即\(sum(LCA)-sum(fa_{LCA})\)
将这些加起来就是这条路径上对应主席树的位置。
即将查询时将原本的
sum(ls(u))-sum(ls(v))
改为:
sum(ls(u))+sum(ls(v))-sum(ls(lca))-sum(ls(falca))
就可以了。
#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
x=0;char ch=getchar();bool f=false;
while(!isdigit(ch)) f|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
x=f?-x:x;return;
}
template <typename T>
inline void print(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) print(x/10);
putchar(x%10^48);return;
}
const int N=1e5+3,M=1e5+3;
struct Seg_Tree{
int ls,rs,sum;
#define ls(x) c[x].ls
#define rs(x) c[x].rs
#define sum(x) c[x].sum
}c[N*32];
int rt[N],cnt,head[N],to[N<<1],Next[N<<1],tot,n,m,len;
int a[N],b[N],siz[N],son[N],fa[N],top[N],dep[N];
//Graph
inline void Add_edge(int u,int v){Next[++tot]=head[u],head[u]=tot,to[tot]=v;return;}
//Seg_Tree
inline void Push_up(int x){sum(x)=sum(ls(x))+sum(rs(x));return;}
inline void Build(int &x,int l,int r){
x=++cnt;
if(l==r) return;
int mid=(l+r)>>1;
Build(ls(x),l,mid),Build(rs(x),mid+1,r);
}
inline void Insert(int &x,int pre,int l,int r,int q){
x=++cnt;c[x]=c[pre];
if(l==r){sum(x)+=1;return;}
int mid=(l+r)>>1;
if(mid>=q) Insert(ls(x),ls(pre),l,mid,q);
else Insert(rs(x),rs(pre),mid+1,r,q);
Push_up(x);return;
}
inline int Query(int u,int v,int lca,int falca,int l,int r,int k){
if(l==r) return b[l];
int mid=(l+r)>>1,tep=sum(ls(u))+sum(ls(v))-sum(ls(lca))-sum(ls(falca));
if(tep>=k) return Query(ls(u),ls(v),ls(lca),ls(falca),l,mid,k);
else return Query(rs(u),rs(v),rs(lca),rs(falca),mid+1,r,k-tep);
}
//Tree Chain Partition
inline void Dfs1(int x,int f){
fa[x]=f,siz[x]=1,dep[x]=dep[f]+1;
for(register int i=head[x];i;i=Next[i]){
int y=to[i];
if(y==f) continue;
Dfs1(y,x);siz[x]+=siz[y];
if(siz[y]>siz[son[x]]) son[x]=y;
}
return;
}
inline void Dfs2(int x){
Insert(rt[x],rt[fa[x]],1,len,a[x]);
top[x]=(son[fa[x]]==x ? top[fa[x]] : x);
if(son[x]) Dfs2(son[x]);
for(register int i=head[x];i;i=Next[i]){
int y=to[i];
if(y==fa[x]||y==son[x]) continue;
Dfs2(y);
}
return;
}
inline int LCA(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]>dep[top[v]]) u=fa[top[u]];
else v=fa[top[v]];
}
return dep[u] > dep[v] ? v : u;
}
int main(){
// system("fc my.out P2633_1.out");
// freopen("P2633_1.in","r",stdin);
// freopen("my.out","w",stdout);
read(n),read(m);
for(register int i=1;i<=n;++i) read(a[i]),b[i]=a[i];
sort(b+1,b+n+1);len=unique(b+1,b+n+1)-(b+1);
for(register int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+len+1,a[i])-b;
Build(rt[0],1,len);
for(register int i=1;i<n;++i){
int u,v;read(u),read(v);
Add_edge(u,v),Add_edge(v,u);
}
Dfs1(1,0);Dfs2(1);int last=0;
while(m--){
int u,v,k;
read(u),read(v),read(k);u^=last;
assert(u<=n);
int lca=LCA(u,v);
last=Query(rt[u],rt[v],rt[lca],rt[fa[lca]],1,len,k);
print(last),putchar('\n');
}
return 0;
}