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;
    } 
    
  • 相关阅读:
    windows系统历年高危漏洞
    安全产品分类
    防火墙
    UTM(统一威胁管理)
    ORA-39127: 调用 "WMSYS"."LT_EXPORT_PKG"."SCHEMA_INFO_EXP" 时发生意外错误
    oracle如何查看当前有哪些用户连接到数据库
    LINUX修改主机名
    删除Oracle用户及表空间
    Oracle AWR报告详细分析--比较详细
    RMAN优缺点及RMAN备份及恢复步骤
  • 原文地址:https://www.cnblogs.com/fisherss/p/12230425.html
Copyright © 2011-2022 走看看