BZOJ2588: Spoj 10628. Count on a tree

裸的树上主席树。一般的主席树每个节点相当于一个前缀和,树上主席树每个节点相当于到根的和,可持久化的时候以树上的父亲为上一个版本。

注意最后一行行末不能输出换行,否则会PE。

upd: 用可持久化trie重写了一遍,和主席树本质相同写法不同,变快了。

#include<algorithm>
#include<cstdio>
#define lb lower_bound
using namespace std;
const int N=1e5+5;
typedef struct node*ptr;
struct node{
	ptr i,j;int s;
}e[N*17];
ptr a=e,f[N];
void ins(int j,ptr*o){
	for(int i=16;~i;--i){
		*++a=**o,*o=a;
		if(j>>i&1)o=&(*o)->j;
		else
			++(*o)->s,o=&(*o)->i;
	}
}
int ask(int k,ptr s,ptr t,ptr u,ptr v){
	int j=0;
	for(int i=16;~i;--i){
		int l=s->s+t->s-u->s-v->s;
		if(k<=l)s=s->i,t=t->i,u=u->i,v=v->i;
		else
			k-=l,j|=1<<i,s=s->j,t=t->j,u=u->j,v=v->j;
	}
	return j;
}
struct edge{
	int v;edge*s;
}z[N*2];
edge*b=z,*h[N];
void ins(int u,int v){
	edge s={v,h[u]};
	*(h[u]=b++)=s;
}
typedef int arr[N];
arr w,p,d,r,y,c,g;
void dfs1(int u){
	f[u]=f[p[u]];
	ins(w[u],f+u);
	r[u]=1;
	for(edge*i=h[u];i;i=i->s)
		if(i->v!=p[u]){
			d[i->v]=d[p[i->v]=u]+1;
			dfs1(i->v);
			r[u]+=r[i->v];
			if(r[i->v]>r[c[u]])
				c[u]=i->v;
		}
}
int lca(int s,int t){
	for(;y[s]!=y[t];s=p[y[s]])
		if(d[y[s]]<d[y[t]])s^=t,t^=s,s^=t;
	return d[s]<d[t]?s:t;
}
struct buf{
	char z[1<<23],*s;
	char e[9<<17],*p;
	buf():s(z),p(e){
		z[fread(z,1,sizeof z,stdin)]=0;
	}
	~buf(){fwrite(e,1,p-e,stdout);}
	operator int(){
		int x=0;
		while(*s<48)++s;
		while(*s>32)
			x=x*10+*s++-48;
		return x;
	}
	void out(int x){
		static char z[12];
		char*i=z;
		if(!x)*p++=48;
		else{
			while(x){
				int y=x/10;
				*i++=x-y*10+48,x=y;
			}
			while(i!=z)*p++=*--i;
		}
	}
}it;
int main(){
	*(*f=e)=(node){e,e};
	int n=it,m=it;
	for(int i=1;i<=n;++i)
		g[i-1]=w[i]=it;
	sort(g,g+n);
	for(int i=1;i<=n;++i)
		w[i]=lb(g,g+n,w[i])-g;
	for(int i=2;i<=n;++i){
		int s=it,t=it;
		ins(s,t),ins(t,s);
	}
	dfs1(1);
	for(int i=1;i<=n;++i)
		if(c[p[i]]!=i)
			for(int j=i;j;j=c[j])y[j]=i;
	int l=0;
	while(m--){
		int s=it^l,t=it,u=lca(s,t);
		it.out(l=g[ask(it,f[s],f[t],f[u],f[p[u]])]);
		if(m)*it.p++=10;
	}
}
posted @ 2016-07-19 00:07  f321dd  阅读(274)  评论(0编辑  收藏  举报