P2633|主席树+dfs序+树链剖分求lca+离散化
Posted fisherss
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2633|主席树+dfs序+树链剖分求lca+离散化相关的知识,希望对你有一定的参考价值。
不知道为什么会RE。。
待补
思路:链上求u和v两点路径第k小利用lca就转变为了 U+V-LCA-FA(LCA) 上的第k小,这因为每个点的主席树的root是从其父转移来的。可以用树链剖分求lca;在dfs序上建立主席树将树上问题转变为区间问题,询问的时候用主席树求区间k小值。
终于能写出这种题了,开心!
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+100;
int n,m,e = 1,num,ans=0;
int mp[maxn],b[maxn],root[maxn];
vector<int> g[maxn];
/* 父亲, 深度, 子节点数, 重儿子, dfs序, dfs映射,链头, 链尾 */
int fa[maxn],depth[maxn],sz[maxn],son[maxn],id[maxn],rk[maxn],top[maxn],bot[maxn];
int cnt = 0;
struct Node{int v,lc,rc;}T[maxn*24];
struct A{
int x,idx;
bool operator < (const A &temp)const{
return x < temp.x;
}
}a[maxn];
int ranks[maxn];
//树链剖分求lca部分
void dfs1(int x,int deep){
depth[x] = deep;
sz[x] = 1;
for(int li = 0;li<g[x].size();li++){
int i = g[x][li];
if(i == fa[x]) continue;
fa[i] = x;
dfs1(i,deep+1);
sz[x] += sz[i];
if(sz[i] > sz[son[x]]) son[x] = i;
}
}
void dfs2(int x,int tp){
top[x] = tp;
id[x] = ++cnt;
rk[cnt] = x;
if(son[x]) dfs2(son[x],tp),bot[x] = bot[son[x]];
else bot[x] = x;
for(int li=0;li<g[x].size();li++){
int i = g[x][li];
if(i != fa[x] && i != son[x])
dfs2(i,i);
}
}
int lca(int u,int v){
while(top[u] != top[v]){
if(depth[top[u]] < depth[top[v]]) swap(u,v);
u = fa[top[u]];
}
if(depth[u] < depth[v]) return u;
return v;
}
//主席树插入insert
void insert(int pre,int cur,int pos,int l,int r){
if(l == r){
T[cur].v = T[pre].v + 1;
return;
}
int mid = (l + r) >> 1;
if(pos <= mid){
T[cur].lc = ++e;
T[cur].rc = T[pre].rc;
insert(T[pre].lc,T[cur].lc,pos,l,mid);
}else{
T[cur].rc = ++e;
T[cur].lc = T[pre].lc;
insert(T[pre].rc,T[cur].rc,pos,mid+1,r);
}
T[cur].v = T[T[cur].lc].v + T[T[cur].rc].v;
}
//主席树求第k小
int kth(int ql,int qr,int LCA,int FLCA,int k,int l,int r){
if(l == r) return l;
int mid = (l + r) >> 1;
int sum = T[T[ql].lc].v + T[T[qr].lc].v + T[T[LCA].lc].v - T[T[FLCA].lc].v;
if(sum >= k) return kth(T[ql].lc,T[qr].lc,T[LCA].lc,T[FLCA].lc,k,l,mid);
else return kth(T[ql].rc,T[qr].rc,T[LCA].rc,T[FLCA].rc,k-sum,mid+1,r);
}
//dfs序上建树
void dfs(int u){
root[u] = ++e;
insert(root[fa[u]],root[u],b[u],1,num);
for(int i=0;i<g[u].size();i++){
int v = g[u][i];
if(v!=fa[u]) dfs(v);
}
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i].x;
a[i].idx = i;
}
//离散化
sort(a+1,a+n+1);
b[a[1].x] = ++num;
mp[num] = a[1].x;
for(int i=2;i<=n;i++){
if(a[i].x != a[i-1].x) ++num;
b[a[i].idx] = num; //b数组保存新的编号
mp[num] = a[i].x; //mp数组存储原始权值
}
int u,v,k;
for(int i=1;i<n;i++){
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs1(1,1);
dfs2(1,1);
dfs(1);
while(m--){
cin>>u>>v>>k;
u ^= ans;
int LCA = lca(u,v);
ans = mp[kth(root[u],root[v],root[LCA],root[fa[LCA]],k,1,num)];
cout<<ans<<endl;
}
return 0;
}
以上是关于P2633|主席树+dfs序+树链剖分求lca+离散化的主要内容,如果未能解决你的问题,请参考以下文章