zoukankan      html  css  js  c++  java
  • 长链剖分 解 k级祖先问题

    概念

    长链剖分, 和重链剖分一样是一种链剖分, 只不过重儿子变成了长儿子。

    称一个点的子树深度(这个概念是我yy的,在其他地方不一定适用)为:以这个点为根的子树中所有节点深度的最大值。
    一个点的长儿子就是这个点的儿子中子树深度最大的那个儿子。

    常见性质

    1.对树长链剖分后, 所有链的 (size) ( (length) ) 之和为树的节点个数。
    显然成立
    2.一个点的 (k) 级祖先所在链的长度 (geq k)
    若这个点的 (k) 祖先与其在同一链中, 则性质成立。
    若反之,则可以推出这个点的 (k) 祖先的儿子们的最大子树深度大于 (k), 性质成立。

    算法流程

    [妙的一匹 ---蒟蒻博主 ]

    前置定义
    定义 (highbit(n))(log_2(n)) 的整数部分。
    假设要求节点 (x)(k) 级祖先。
    (r = 2^{highbit(k)})

    真 · 流程
    求出 (x)(r) 级祖先 (y), 问题转化为求 (y)(k-r) 级祖先。(由于 (r)(2) 的整次幂, 所以可以倍增处理后 (O(1)) 回答)

    由二进制的性质, 可知 (k-r<r)
    常见性质2(y) 所在链的长度 (geq r)

    故预处理出每个链 (L) 链顶的 (1 leq k leq length(L)) 级祖先和(1 leq k leq length(L)) 级儿子, 可以保证 (y)(k-r) 级祖先必被包含其中。


    时间复杂度分析
    倍增预处理 (O(nlog n))
    预处理每个链 (L)(length(L)) 个祖先和儿子, 复杂度是 (O(sum_{L} length(L)) = O(n))
    显而易见, 经过预处理之后, 对某个 (k) 级祖先问题的回答是可以做到 (O(1)) 的。


    板子题
    AC代码

    // 注意, 以一个点 x 为顶端的链的长度为 treedep[x]-dep[x]+1;
    // 由于这个 sb 错误我调了很久qwq
    // 希望看这篇博文的人引以为戒 qwq
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 5e5+15;
    
    #define ui unsigned int
    ui s;
    inline ui get(ui x) {
    	x ^= x << 13;
    	x ^= x >> 17;
    	x ^= x << 5;
    	return s = x; 
    }
    
    int n,q,rt;
    vector<int>e[maxn],ks[maxn],kf[maxn];
    int treedep[maxn],dep[maxn],son[maxn],top[maxn];
    int f[21][maxn];
    
    void po1(int x,int fa,int Dep) {
    	treedep[x]=dep[x]=Dep;
    	f[0][x]=fa;
    	for(int i=0;i<(int)e[x].size();++i) {
    		int y=e[x][i]; if(y==fa) continue;
    		po1(y,x,Dep+1);
    		if(treedep[y]>treedep[son[x]]) treedep[x]=treedep[son[x]=y];
    	}
    }
    void po2(int x,int tp) {
    	top[x]=tp;
    	if(son[x]) po2(son[x],tp);
    	for(int i=0;i<(int)e[x].size();++i) {
    		int y=e[x][i]; if(y==f[0][x]||y==son[x]) continue;
    		po2(y,y);
    	}
    }
    
    int highbit[maxn];
    int kfa(int x,int k) {
    	if(!k) return x;
    	int r=highbit[k];
    	x=f[r][x];
    	k-=(1<<r);
    	if(dep[x]-k<dep[top[x]])
    		return kf[top[x]][dep[top[x]]-(dep[x]-k)];
    	else
    		return ks[top[x]][(dep[x]-k)-dep[top[x]]];
    }
    
    int ans[5000005];
    int main()
    {
    	cin>>n>>q>>s;
    	for(int i=1;i<=n;++i) {
    		int ff;scanf("%d",&ff);
    		if(ff) e[ff].push_back(i);
    		else rt=i;
    	}
    	po1(rt,0,1);
    	po2(rt,rt);
    	for(int k=1;k<=20;++k)
    		for(int i=1;i<=n;++i)
    			f[k][i] = f[k-1][f[k-1][i]];
    	for(int x=1;x<=n;++x) if(x==top[x]) {
    		int ns=x, nf=x;
    		for(int i=0;i<=treedep[x]-dep[x]+1;++i) {
    			ks[x].push_back(ns), kf[x].push_back(nf);
    			ns=son[ns], nf=f[0][nf];
    		}
    	}
    	for(int i=1;i<=n;++i) highbit[i] = log2(i);
    	for(int i=1;i<=q;++i) {
    		int x=((get(s) xor ans[i-1]) % n)+1;
    		int k=(get(s) xor ans[i-1])%dep[x];
    		ans[i] = kfa(x,k);
    	}
    	long long ANS = 0ll;
    	for(int i=1;i<=q;++i) ANS ^= 1ll*i*ans[i];
    	cout << ANS;
    	return 0;
    }
    
  • 相关阅读:
    笔记-归并排序
    Repeated Substring Pattern
    Assign Cookies
    Number of Boomerangs
    Paint Fence
    Path Sum III
    Valid Word Square
    Sum of Two Integers
    Find All Numbers Disappeared in an Array
    First Unique Character in a String
  • 原文地址:https://www.cnblogs.com/tztqwq/p/12789673.html
Copyright © 2011-2022 走看看