zoukankan      html  css  js  c++  java
  • BZOJ2588: Spoj 10628. Count on a tree(主席树)


    BZOJ2588: Spoj 10628. Count on a tree##

      Time Limit: 12 Sec
      Memory Limit: 128 MB

    Description###

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

    Input###

       第一行两个整数N,M。
       第二行有N个整数,其中第i个整数表示点i的权值。
       后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
       最后M行每行两个整数(u,v,k),表示一组询问。
     

    Output###

       M行,表示每个询问的答案。最后一个询问不输出换行符
     

    Sample Input###

      8 5
      105 2 9 3 8 5 7 7
      1 2
      1 3
      1 4
      3 5
      3 6
      3 7
      4 8
      2 5 1
      0 5 2
      10 5 3
      11 5 4
      110 8 2
     

    Sample Output###

      2
      8
      9
      105
      7
        

    HINT

       N,M<=100000
       暴力自重。。。
      

    题目地址:BZOJ2588: Spoj 10628. Count on a tree

    题目大意: 已经很简洁了

    题解:

      主席树
      先对所有点权离散化一遍(因为要建权值线段树)
      然后对树上的每一个节点到根的路径建一棵权值线段树
      然后空间为 (n^2log_{2}n)  显然 (MLE)
      因为这些树形态结构都是一样的
      而且对于每个非根节点
      他所构成的权值线段树只与他父亲差了一个数(他自己的点权)
      所以可以按 (dfs) 序来建主席树,进行加减运算(主席树特性)
      那么x,y两点之间的路径上所构成的权值线段树就可以表示成

    [Tree[x]+Tree[y]-Tree[lca(x,y)]-Tree[fa[lca(x,y)] ]

      (画图验证)
      具体看代码


    AC代码

    #include <cstdio> 
    #include <algorithm>
    #include <map>
    using namespace std;
    const int N=1e5+5,M=18e5+5;
    int n,Q,New,cnt,ans;
    int last[N],val[N],hash[N];
    int rt[N],ls[M],rs[M],sum[M];
    map<int,int> mp;
    struct edge{
    	int to,next;
    }e[N<<1];
    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;
    }
    inline void add_edge(int u,int v){
    	e[++cnt]=(edge){v,last[u]};last[u]=cnt;
    	e[++cnt]=(edge){u,last[v]};last[v]=cnt;
    }
    int ind,pos[N],sop[N],dep[N],fa[N][18];
    void dfs(int u){
    	pos[u]=++ind;
    	sop[ind]=u;
    	for(int i=last[u];i;i=e[i].next){
    		int v=e[i].to;
    		if(v==fa[u][0])continue;
    		fa[v][0]=u;
    		dep[v]=dep[u]+1;
    		dfs(v);
    	}
    }
    int lca(int a,int b){
    	if(dep[a]<dep[b])swap(a,b);
    	for(int i=17;i>=0;i--)
    		if(dep[fa[a][i]]>=dep[b])
    			a=fa[a][i];
    	for(int i=17;i>=0;i--)
    		if(fa[a][i]!=fa[b][i])
    			a=fa[a][i],b=fa[b][i];
    	if(a==b)return a;
    	return fa[a][0];
    }
    int sz;
    void build(int l,int r,int pre,int &now,int num){
    	now=++sz;
    	sum[now]=sum[pre]+1;
    	if(l==r)return;
    	ls[now]=ls[pre];
    	rs[now]=rs[pre];
    	int mid=(l+r)>>1;
    	if(num<=mid)build(l,mid,ls[pre],ls[now],num);
    	else build(mid+1,r,rs[pre],rs[now],num);
    }
    int solve(int u,int v,int rk){
    	int a=u,b=v,c=lca(u,v),d=fa[c][0];
    	a=rt[pos[a]],b=rt[pos[b]],c=rt[pos[c]],d=rt[pos[d]];
    	int l=1,r=New;
    	while(l<r){
    		int mid=(l+r)>>1;
    		int tmp=sum[ls[a]]+sum[ls[b]]-sum[ls[c]]-sum[ls[d]];
    		if(tmp>=rk){
    			r=mid;
    			a=ls[a],b=ls[b],c=ls[c],d=ls[d];
    		}else{
    			l=mid+1;rk-=tmp;
    			a=rs[a],b=rs[b],c=rs[c],d=rs[d];
    		}
    	}
    	return hash[l];
    }
    int main(){
    	n=read();Q=read();
    	for(int i=1;i<=n;i++)
    		val[i]=hash[i]=read();
    	sort(hash+1,hash+n+1);
    	New=unique(hash+1,hash+n+1)-hash-1;
    	for(int i=1;i<=New;i++)
    		mp[hash[i]]=i;
    	for(int i=1;i<=n;i++)
    		val[i]=mp[val[i]];
    	for(int i=1;i<n;i++){
    		int u=read(),v=read();
    		add_edge(u,v);
    	}
    	dep[1]=1;
    	dfs(1);
    	for(int j=1;j<=17;j++)
    		for(int i=1;i<=n;i++)
    			fa[i][j]=fa[fa[i][j-1]][j-1];
    	for(int i=1;i<=n;i++)
    		build(1,New,rt[pos[fa[sop[i]][0]]],rt[i],val[sop[i]]);
    	while(Q--){
    		int u=read()^ans,v=read(),rk=read();
    		ans=solve(u,v,rk);
    		printf("%d",ans);
    		if(Q)puts("");
    	}
    	return 0;
    }
    


      作者:skl_win
      出处:https://www.cnblogs.com/shaokele/
      本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    Cookie
    webSocket+HeadBeat
    Javascript-多个数组是否有一样值
    后缀补全用得好,提前下班没烦恼
    Nginx 究竟如何处理事件?
    9 个习惯助你在新的一年更有精力
    一篇文章带你了解 ZooKeeper 架构
    浅析 Nginx 网络事件
    ZooKeeper 入门看这篇就够了
    如何优雅地关闭worker进程?
  • 原文地址:https://www.cnblogs.com/shaokele/p/9514445.html
Copyright © 2011-2022 走看看