首页 > 代码库 > BZOJ2588 Spoj 10628. Count on a tree

BZOJ2588 Spoj 10628. Count on a tree

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

 

 

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

 

 

题目链接:BZOJ2588

     SPOJ10628

 

正解:主席树上树

解题报告:

  考虑主席树上树,每次build都是儿子在父亲的基础上build,然后查询的话就是对于x到y的路径,令$Tx$为$x$对应的线段树,那就是$T_x+T_y-T_{lca}-T_{fa[lca]}$。

  

//It is made by ljh2000
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <string>
#include <complex>
using namespace std;
#define lc t[R].ls
typedef long long LL;
typedef long double LB;
typedef complex<double> C;
const double pi = acos(-1);
const int MAXN = 200011;
const int MAXM = 400011;
int n,m,ecnt,first[MAXN],to[MAXM],next[MAXM],deep[MAXN],ans;
int a[MAXN],b[MAXN],c[MAXN],L,f[MAXN][18],cnt,root[MAXN];
inline void link(int x,int y){ next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; }
struct node{
	int ls,rs,num;
}t[7000011];

inline int getint(){
    int w=0,q=0; char c=getchar(); while((c<‘0‘||c>‘9‘) && c!=‘-‘) c=getchar();
    if(c==‘-‘) q=1,c=getchar(); while (c>=‘0‘&&c<=‘9‘) w=w*10+c-‘0‘,c=getchar(); return q?-w:w;
}

inline void build(int &rt,int last,int l,int r,int pos){
	rt=++cnt; t[rt]=t[last]; t[rt].num++;
	if(l==r) return ; int mid=(l+r)>>1;
	if(pos<=mid) build(t[rt].ls,t[last].ls,l,mid,pos);
	else build(t[rt].rs,t[last].rs,mid+1,r,pos);
}

inline void dfs(int x,int fa){
	build(root[x],root[fa],1,L,c[x]);//以父亲节点为last,更新主席树
	//printf("%d\n",cnt);
	for(int i=first[x];i;i=next[i]) {
		int v=to[i]; if(v==fa) continue;
		f[v][0]=x; deep[v]=deep[x]+1;
		dfs(v,x);
	}
}

inline int lca(int x,int y){
	if(deep[x]<deep[y]) swap(x,y); int t=0; while((1<<t)<=deep[x]) t++; t--;
	for(int i=t;i>=0;i--) if(deep[x]-(1<<i)>=deep[y]) x=f[x][i]; if(x==y) return y;
	for(int i=t;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0];
}

inline int query(int x1,int x2,int j1,int j2,int l,int r,int k){
	if(l==r) return l;
	int R=x1; int cp=t[lc].num; int mid=(l+r)>>1;
	R=x2; cp+=t[lc].num;
	R=j1; cp-=t[lc].num;
	R=j2; cp-=t[lc].num;
	if(k<=cp) return query(t[x1].ls,t[x2].ls,t[j1].ls,t[j2].ls,l,mid,k);
	else return query(t[x1].rs,t[x2].rs,t[j1].rs,t[j2].rs,mid+1,r,k-cp);
}

inline void work(){
	n=getint(); m=getint(); for(int i=1;i<=n;i++) b[i]=a[i]=getint();
	sort(b+1,b+n+1); L=unique(b+1,b+n+1)-b-1; 
	for(int i=1;i<=n;i++)
		c[i]=lower_bound(b+1,b+L+1/*!!!*/,a[i])-b;

	int x,y,z,G; ans=0;
	for(int i=1;i<n;i++) { x=getint(); y=getint(); link(x,y); link(y,x); }
	deep[1]=1; dfs(1,0);
	for(int j=1;j<=17;j++)
		for(int i=1;i<=n;i++)
			f[i][j]=f[f[i][j-1]][j-1];

	while(m--) {
		x=getint(); y=getint(); z=getint();	x^=ans;
		G=lca(x,y);
		ans=b[ query(root[x],root[y],root[G],root[ f[G][0] ],1,L,z) ];
		printf("%d",ans);
		if(m!=0) puts("");
	}
}

int main()
{
    work();
    return 0;
}

  

BZOJ2588 Spoj 10628. Count on a tree