BZOJ2588 主席树 + 树上差分
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 = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();} while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;} const double eps = 1e-9; const int maxn = 1e5 + 10; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,M,K; int val[maxn],Hash[maxn],tot,cnt,T[maxn]; struct Edge{ int to,next; }edge[maxn * 2]; int head[maxn],TOT; void init(){ for(int i = 0 ; i <= N ; i ++) head[i] = -1; TOT = tot = 0; } 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 * 60]; void newnode(int &t){ t = ++tot; tree[t].sum = 0; } void Build(int &t,int l,int r){ newnode(t); if(l == r) return; int m = l + r >> 1; Build(tree[t].lt,l,m); Build(tree[t].rt,m + 1,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 >> 1; if(p <= m) update(tree[t].lt,tree[pre].lt,l,m,p); else update(tree[t].rt,tree[pre].rt,m + 1,r,p); } const int SP = 20; int fa[maxn][SP],dep[maxn]; void dfs(int u,int la){ int p = lower_bound(Hash + 1,Hash + 1 + cnt,val[u]) - Hash; update(T[u],T[la],1,cnt,p); fa[u][0] = la; dep[u] = dep[la] + 1; for(int i = 1; i < SP; i ++) fa[u][i] = fa[fa[u][i - 1]][i - 1]; 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 = 0 ; i < SP; i ++) if(t & (1 << i)) u = fa[u][i]; for(int i = SP - 1; i >= 0 ; i --){ int uu = fa[u][i],vv = fa[v][i]; if(uu != vv){ u = uu; v = vv; } } return u == v?u:fa[u][0]; } 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 >> 1; 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 + 1,r,k - num); } int main(){ Sca2(N,M); init(); for(int i = 1; i <= N ; i ++) val[i] = Hash[i] = read(); for(int i = 1; i <= N - 1; i ++){ int u = read(),v = read(); add(u,v); add(v,u); } sort(Hash + 1,Hash + 1 + N); cnt = unique(Hash + 1,Hash + 1 + N) - Hash - 1; Build(T[0],1,cnt); int root = 1; dfs(root,0); int ans = 0; for(int i = 1; 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][0]],1,cnt,k)]; Pri(ans); } return 0; }