BZOJ2588 主席树 + 树上差分

时间:2023-03-08 20:55:14

https://www.lydsy.com/JudgeOnline/problem.php?id=2588

题意:强制在线的询问树链权值第K小(无修)

这种类似于第K小的题,一般容易想到主席树,但是树链并不能不是一个按顺序的序列,使用树链剖分也不太容易维护几条链之间的第K小关系。

但是可以从主席树的前缀和思想入手,一般情况的主席树,查询的时候是query(R) - query(L - 1)来询问区间内的数值数量,在这一题里面,可以考虑到树上差分,从树根开始,以每一个点的父亲为前缀建立主席树。

然后查询的时候转变为query(u) + query(v) - query(lca(u,v,)) - query(fa(lca(u,v))) 就可以了。

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
int read(){int x = ,f = ;char c = getchar();while (c<'' || c>''){if (c == '-') f = -;c = getchar();}
while (c >= ''&&c <= ''){x = x * + c - '';c = getchar();}return x*f;}
const double eps = 1e-;
const int maxn = 1e5 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,K;
int val[maxn],Hash[maxn],tot,cnt,T[maxn];
struct Edge{
int to,next;
}edge[maxn * ];
int head[maxn],TOT;
void init(){
for(int i = ; i <= N ; i ++) head[i] = -;
TOT = tot = ;
}
void add(int u,int v){
edge[TOT].to = v;
edge[TOT].next = head[u];
head[u] = TOT++;
}
struct Tree{
int lt,rt,sum;
}tree[maxn * ];
void newnode(int &t){
t = ++tot;
tree[t].sum = ;
}
void Build(int &t,int l,int r){
newnode(t);
if(l == r) return;
int m = l + r >> ;
Build(tree[t].lt,l,m); Build(tree[t].rt,m + ,r);
}
void update(int &t,int pre,int l,int r,int p){
newnode(t);
tree[t] = tree[pre]; tree[t].sum++;
if(l == r) return;
int m = l + r >> ;
if(p <= m) update(tree[t].lt,tree[pre].lt,l,m,p);
else update(tree[t].rt,tree[pre].rt,m + ,r,p);
}
const int SP = ;
int fa[maxn][SP],dep[maxn];
void dfs(int u,int la){
int p = lower_bound(Hash + ,Hash + + cnt,val[u]) - Hash;
update(T[u],T[la],,cnt,p);
fa[u][] = la; dep[u] = dep[la] + ;
for(int i = ; i < SP; i ++) fa[u][i] = fa[fa[u][i - ]][i - ];
for(int i = head[u]; ~i ; i = edge[i].next){
int v = edge[i].to;
if(v == la) continue;
dfs(v,u);
}
}
int lca(int u,int v){
if(dep[u] < dep[v]) swap(u,v);
int t = dep[u] - dep[v];
for(int i = ; i < SP; i ++) if(t & ( << i)) u = fa[u][i];
for(int i = SP - ; i >= ; i --){
int uu = fa[u][i],vv = fa[v][i];
if(uu != vv){
u = uu; v = vv;
}
}
return u == v?u:fa[u][];
}
int query(int u,int v,int f,int ff,int l,int r,int k){
if(l >= r) return l;
int num = tree[tree[u].lt].sum + tree[tree[v].lt].sum - tree[tree[f].lt].sum - tree[tree[ff].lt].sum;
int m = l + r >> ;
if(k <= num) return query(tree[u].lt,tree[v].lt,tree[f].lt,tree[ff].lt,l,m,k);
else return query(tree[u].rt,tree[v].rt,tree[f].rt,tree[ff].rt,m + ,r,k - num);
}
int main(){
Sca2(N,M); init();
for(int i = ; i <= N ; i ++) val[i] = Hash[i] = read();
for(int i = ; i <= N - ; i ++){
int u = read(),v = read();
add(u,v); add(v,u);
}
sort(Hash + ,Hash + + N);
cnt = unique(Hash + ,Hash + + N) - Hash - ;
Build(T[],,cnt);
int root = ; dfs(root,);
int ans = ;
for(int i = ; i <= M; i ++){
int u = read() ^ ans,v = read(),k = read();
int l = lca(u,v);
//cout << u << " " << v << " " << l << " " << fa[l][0] << endl;
ans = Hash[query(T[u],T[v],T[l],T[fa[l][]],,cnt,k)];
Pri(ans);
}
return ;
}