zoukankan      html  css  js  c++  java
  • [Bzoj2588]Count on a tree(主席树+LCA)

    Description

    给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文

    Solution

    类似区间第K大,主席树套个LCA就行了

    对于树上两个节点x和y,设他们的LCA为a,且a的父节点为b

    那么x到y的这段区间就为((T[x]-T[b])+(T[x]-T[b])+T[a]) (节点a会重复减去)

    (T[i])表示以(i)节点建立的线段树

    Code

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #define N 100010
    using namespace std;
    
    struct info{int to,nex;}e[N*2];
    int n,m,A[N],rank[N],T[N],ls[N*20],rs[N*20],sum[N*20],tot,cnt,preAns;
    int _log,fa[N],head[N],f[N][20],dep[N];
    
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    
    void Link(int u,int v){
    	e[++tot].nex=head[u];
    	e[tot].to=v;
    	head[u]=tot;
    }
    
    void update(int last,int p,int l,int r,int &rt){
    	rt=++tot;
    	ls[rt]=ls[last],rs[rt]=rs[last],sum[rt]=sum[last]+1;
    	if(l==r) return;
    	int m=(l+r)>>1;
    	if(p<=m) update(ls[last],p,l,m,ls[rt]);
    	else update(rs[last],p,m+1,r,rs[rt]);
    }
    
    void dfs(int u,int fa){
    	update(T[fa],A[u],1,cnt,T[u]);
    	for(int i=1;i<=_log;++i)
    		f[u][i]=f[f[u][i-1]][i-1];
    	for(int i=head[u];i;i=e[i].nex){
    		int v=e[i].to;
    		if(v==fa) continue;
    		dep[v]=dep[u]+1;
    		f[v][0]=u;
    		dfs(v,u);
    	}
    }
    
    int LCA(int u,int v){
    	if(dep[u]>dep[v]) swap(u,v);
    	int d=dep[v]-dep[u];
    	
    	for(int i=0;i<=_log;++i)
    		if(d&(1<<i)) v=f[v][i];
    	if(u==v) return v;
    	
    	for(int i=_log;i>=0;--i)
    		if(f[u][i]!=f[v][i]){
    			u=f[u][i];
    			v=f[v][i];
    		}
    	return f[u][0];
    }
    
    int query(int l,int r,int x,int y,int a,int b,int k){
    	if(l==r) return l;
    	int m=(l+r)>>1,d=sum[ls[x]]-sum[ls[b]]+sum[ls[y]]-sum[ls[a]];
    	if(d>=k) return query(l,m,ls[x],ls[y],ls[a],ls[b],k);
    	else return query(m+1,r,rs[x],rs[y],rs[a],rs[b],k-d);
    }
    
    int main(){
    	n=read(),m=read();
    	_log=log(n)/log(2);
    	for(int i=1;i<=n;++i) A[i]=rank[i]=read();
    	sort(rank+1,rank+n+1);
    	cnt=unique(rank+1,rank+n+1)-(rank+1);
    	for(int i=1;i<=n;++i) A[i]=lower_bound(rank+1,rank+cnt+1,A[i])-rank;
    	for(int i=1;i<n;++i){
    		int u=read(),v=read();
    		Link(u,v);Link(v,u);
    	}
    	tot=0;
    	dfs(1,0);
    	while(m--){
    		int u=read()^preAns,v=read(),k=read();
    		int lca=LCA(u,v);
    		printf("%d",preAns=rank[query(1,cnt,T[u],T[v],T[lca],T[f[lca][0]],k)]);
            if(m>0) printf("
    ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    计算机网络技术基础2
    java基础
    跨页传递参数或临时表的几种方法
    ASP.NET2.0文件上传以及图片处理总结篇 [转]
    正则表达式
    ASP.NET2.0中WEB应用程序的部署
    比较著名的.net技术论坛名称
    WordPress 插件开发实例 – 详细注释的 Widget 开发例子
    Java Applet签名验证
    Java Logging API Tutorial
  • 原文地址:https://www.cnblogs.com/void-f/p/8414413.html
Copyright © 2011-2022 走看看