zoukankan      html  css  js  c++  java
  • 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;
    } 
    
  • 相关阅读:
    ffmpeg rtmp推流 视频转码
    java日志发展史 log4j slf4j log4j2 jul jcl 日志和各种桥接包的关系
    nginx stream 流转发,可以转发rtmp、mysql访问流,转发rtmp、jdbc请求
    java web http 转https 通过nginx代理访问
    linux 服务器磁盘挂载
    novnc 通过websockify代理 配置多点访问
    linux 文件服务 minio 安装部署配置
    AOP实现原理,手写aop
    java 泛型
    JAVA反射getGenericSuperclass()用法
  • 原文地址:https://www.cnblogs.com/fisherss/p/12230425.html
Copyright © 2011-2022 走看看