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;
} 
posted @ 2020-01-23 11:58  fishers  阅读(203)  评论(0编辑  收藏  举报