zoukankan      html  css  js  c++  java
  • [vijos]lxhgww的奇思妙想——长链剖分模板

    题目大意:

    给定一棵树,询问x的k次祖先。

    思路:

    这是一道长链剖分的模板。
    长链剖分类似于平常树链剖分的模式,但是划分轻重链并不是以size为依据而是以子树内最深度最大的节点为依据,这使得它具有一些重链剖分不具有的性质。
    性质1:所有的链长=n
    性质2:任意一个点的k次祖先所在的链链长(geq)k。
    上面两条性质都很好证,这里不再作多余说明。
    于是考虑如何高效地求解k次祖先,我们在每条链的端点记录两个表,一个表示向下的点有哪些,一个表示向上的链长个点有哪些。
    询问时我们可以将k折半,x首先跳到x的(frac{k}{2})次祖先y,不难发现这时y所在的链长(geq frac{k}{2}),同时它距离x的k次祖先的距离也(leq frac{k}{2}),不难发现这个时候无论y和x的k次祖先在不在一条链上,都可以通过向上或者向下的数组跳到。
    这里的折半操作在实际操作中是利用预处理的倍增数组跳到x的(2^{lfloor{log_2k floor}})次祖先处,不难发现此时单次询问复杂度O(1)。

    #include<bits/stdc++.h>
    
    #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
    #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
    #define debug(x) cout<<#x<<"="<<x<<" "
    #define siz(x) ((int)x.size())
    #define fi first
    #define se second
    #define mk make_pair
    #define pb push_back
    typedef long long ll;
    
    using namespace std;
    
    void File(){
    	freopen("lxhgww.in","r",stdin);
    	freopen("lxhgww.out","w",stdout);
    }
    
    template<typename T>void read(T &_){
    	_=0; T f=1; char c=getchar();
    	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    	for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
    	_*=f;
    }
    
    const int maxn=3e5+10;
    int n,m,Log[maxn],st[maxn][21];
    int beg[maxn],to[maxn<<1],las[maxn<<1],cnte=1;
    int fa[maxn],son[maxn],len[maxn],top[maxn],dep[maxn];
    vector<int>lis[maxn],up[maxn];
    
    void add(int u,int v){
    	las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v;
    	las[++cnte]=beg[v]; beg[v]=cnte; to[cnte]=u;
    }
    
    void dfs1(int u,int f){
    	fa[u]=f;
    	st[u][0]=f;
    	dep[u]=dep[f]+1;
    	for(int i=beg[u];i;i=las[i]){
    		int v=to[i];
    		if(v==f)continue;
    		dfs1(v,u);
    		if(len[v]+1>len[u]){
    			len[u]=len[v]+1;
    			son[u]=v;
    		}
    	}
    }
    
    void dfs2(int u,int t){
    	top[u]=t;
    	lis[t].pb(u);
    	if(son[u])dfs2(son[u],t);
    	for(int i=beg[u];i;i=las[i]){
    		int v=to[i];
    		if(v==fa[u] || v==son[u])continue;
    		dfs2(v,v);
    	}
    	/*if(u==t){
    		int p=u;
    		REP(i,1,len[u]){
    			if(!p)break;
    			up[u].pb(p);
    			p=fa[p];
    		}
    	}*/
    }
    
    void init(){
    	read(n);
    	REP(i,2,n)Log[i]=Log[i/2]+1;
    	int u,v;
    	REP(i,1,n-1)read(u),read(v),add(u,v);
    	dfs1(1,0);
    	dfs2(1,1);
    	for(u=1;u<=n;++u)
    		if(u==top[u])for(int i=1,p=u;i<=len[u] && p;++i,p=fa[p])
    			up[u].pb(p);
    	REP(j,1,20)REP(i,1,n)
    		if((1<<j)<=dep[i]-1)
    			st[i][j]=st[st[i][j-1]][j-1];
    }
    
    int query(int u,int k){
    	if(k>dep[u]-1)return 0;
    	if(!k)return u;
    	u=st[u][Log[k]];
    	k-=1<<Log[k];
    	int d=dep[u]-dep[top[u]];
    	if(k<=d)return lis[top[u]][d-k];
    	else return up[top[u]][k-d];
    }
    
    void work(){
    	read(m);
    	int x,y,ans=0;
    	REP(i,1,m){
    		read(x),read(y);
    		x^=ans; y^=ans;
    		ans=query(x,y);
    		printf("%d
    ",ans);
    	}
    }
    
    int main(){
    	//File();
    	init();
    	work();
    	return 0;
    }
    
    
  • 相关阅读:
    Python 爬虫js加密破解(一) 爬取今日头条as cp 算法 解密
    Python 爬虫实例(2)—— 爬取今日头条
    Python 爬虫实例(1)—— 爬取百度图片
    python 操作redis之——HyperLogLog (八)
    python 操作redis之——有序集合(sorted set) (七)
    Python操作redis系列之 列表(list) (五)
    Python操作redis系列以 哈希(Hash)命令详解(四)
    Python操作redis字符串(String)详解 (三)
    How to Install MySQL on CentOS 7
    Linux SSH远程文件/目录 传输
  • 原文地址:https://www.cnblogs.com/ylsoi/p/10234313.html
Copyright © 2011-2022 走看看