P2633 Count on a tree

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2633 Count on a tree相关的知识,希望对你有一定的参考价值。

P2633 Count on a tree

题意:

给定一棵 n 个节点的树,每个点有一个权值。有 m 个询问,每次给你 u,v,k,你需要回答 u xor last 和 v 这两个节点间第 k 小的点权。

其中last 是上一个询问的答案,定义其初始为 0,即第一个询问的 u 是明文。

题解:

很明显,主席树,而且强制在线(更是主席树)
主席树是维护了一个类似前缀和的数据结构,当要查询线性区间[l,r]的第k小时,用第r个线段树减第l-1个线段树,得到的就是[l,r]之间的权值线段树(因为主席树维护的就是前缀和),然后直接用二分查找第k小就行
在本题中给了一个树,问点u到点v之间的第k小,我们都知道树上差分(应该都知道),我们利用树上差分就可以得到u到v之间的数据
定义s[u]为从根节点到点u节点的主席树,那么u到v之间的所有数值信息的主席树就应该是:
s[u]+s[v]-s[lca[u,v]]-s[fa[lca(u,v)]]
因为需要lca所以要用到倍增,可以在dfs中插入每个点

代码:


#include<bits/stdc++.h>
using namespace std;
#define N 100010
#define M 2000010
int read(){
	int ans=0,w=1;char c=getchar();
	while(c!='-'&&!isdigit(c))c=getchar();
	if(c=='-')w=-1,c=getchar();
	while(isdigit(c))ans=ans*10+c-'0',c=getchar();
	return ans*w;
}
int n,m,s,lastans=0,u,v,tot,cnt;
struct Edge{int v,next;}E[N<<1];
int head[N],a[N],b[N],fa[N][32],dep[N];
int rt[M]={0},ls[M]={0},rs[M]={0},siz[M]={0};
void add(int u,int v){
	E[++tot]=(Edge){v,head[u]};
	head[u]=tot;
}
void modify(int &rt,int lastrt,int l,int r,int val){
	if(!rt)rt=++cnt;
	if(l==r){siz[rt]++;return;}
	int mid=(l+r)>>1;
	if(mid>=val)modify(ls[rt],ls[lastrt],l,mid,val),rs[rt]=rs[lastrt];
	else modify(rs[rt],rs[lastrt],mid+1,r,val),ls[rt]=ls[lastrt];
	siz[rt]=siz[ls[rt]]+siz[rs[rt]];
}
int query(int rt1,int rt2,int rt3,int rt4,int l,int r,int k){
	if(l==r)return l;
	int mid=(l+r)>>1;
	int tmp=siz[ls[rt1]]+siz[ls[rt2]]-siz[ls[rt3]]-siz[ls[rt4]];
	if(tmp>=k)return query(ls[rt1],ls[rt2],ls[rt3],ls[rt4],l,mid,k);
	else return query(rs[rt1],rs[rt2],rs[rt3],rs[rt4],mid+1,r,k-tmp);
}
void dfs(int u,int f){
	dep[u]=dep[f]+1;
	for(int i=head[u];i;i=E[i].next){
		int v=E[i].v;
		if(v==fa[u][0])continue;
		fa[v][0]=u;
		modify(rt[v],rt[u],1,s,a[v]);
		dfs(v,u);
	}
}
int Lca(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	int t=dep[x]-dep[y];
	for(int i=0;(1<<i)<=t;i++)
		if((1<<i)&t)x=fa[x][i];
	for(int i=19;i>=0;i--)
		if(fa[x][i]!=fa[y][i])
			x=fa[x][i],y=fa[y][i];
	if(x==y)return x;
	return fa[x][0];
}
int main(){
	n=read();m=read();
	for(int i=1;i<=n;i++)b[i]=a[i]=read();
	sort(b+1,b+n+1);
	s=unique(b+1,b+n+1)-b;
	for(int i=1;i<n;i++){
		u=read();v=read();
		add(u,v);add(v,u);
	}
	for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+s+1,a[i])-b;
	modify(rt[1],rt[0],1,s,a[1]);
	dfs(1,0);
	int up=log2(n);
	for(int k=1;k<=up;k++)
		for(int i=1;i<=n;i++)
			fa[i][k]=fa[fa[i][k-1]][k-1];
	for(int i=1;i<=m;i++){
		u=read();v=read();int k=read();
		u^=lastans;
		int lca=Lca(u,v);
		int ans=b[query(rt[u],rt[v],rt[lca],rt[fa[lca][0]],1,s,k)];
		printf("%d\\n",ans);
		lastans=ans;
	}
	return 0;
}

以上是关于P2633 Count on a tree的主要内容,如果未能解决你的问题,请参考以下文章

[luogu P2633] Count on a tree

洛谷P2633 Count on a tree

P2633 Count on a tree(主席树)

P2633 Count on a tree 树上主席树

「luogu2633」Count on a tree

「SPOJ10707」Count on a tree II