【题解】Count on a tree

Count on a tree

\(\text{Solution:}\)

就是一个树上静态第 \(k\) 小。

考虑对于一个点 \(x\) 维护一棵主席树,它的信息是 \([root,x].\)

这样对于一条路径 \(<s,t>\) ,它的信息可以用树上差分的思想来统计:

\[cnt=root[s]+root[t]-root[LCA]-root[pa[LCA]] \]

有了这个式子就好办了,树剖 LCA 套上树上差分即可。

时间复杂度 \(O(n\log n).\)

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN=2e5+10;
const int N=(MAXN<<5);
int rt[MAXN],node,siz[MAXN],pa[MAXN];
struct Tr{int ls,rs,sum;}tr[N];
int head[MAXN],tot,top[MAXN],son[MAXN];
struct E{int nxt,to;}e[MAXN];
inline void add(int x,int y){e[++tot]=(E){head[x],y};head[x]=tot;}
int b[MAXN],blen,n,m,a[MAXN],lastans,dep[MAXN];
inline int Min(int x,int y){return x<y?x:y;}
inline int Max(int x,int y){return x>y?x:y;}
inline int read() {
	int s=0,w=1;
	char ch=getchar();
	while(!isdigit(ch)) {
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(isdigit(ch)) {
		s=s*10-48+ch;
		ch=getchar();
	}
	return w*s;
}
inline int getpos(int v){return lower_bound(b+1,b+blen+1,v)-b;}
int change(int x,int l,int r,int pos,int v){
	int p=++node;
	tr[p]=tr[x];
	tr[p].sum+=v;
	if(l==r)return p;
	int mid=(l+r)>>1;
	if(pos<=mid)tr[p].ls=change(tr[p].ls,l,mid,pos,v);
	else tr[p].rs=change(tr[p].rs,mid+1,r,pos,v);
	return p;
}
int query(int x,int y,int l,int fl,int L,int R,int k){
	//cnt=x+y-l-fl
	if(L==R)return L;
	int mid=(L+R)>>1;
	int cnt=tr[tr[x].ls].sum+tr[tr[y].ls].sum-tr[tr[l].ls].sum-tr[tr[fl].ls].sum;
	if(k<=cnt)return query(tr[x].ls,tr[y].ls,tr[l].ls,tr[fl].ls,L,mid,k);
	else return query(tr[x].rs,tr[y].rs,tr[l].rs,tr[fl].rs,mid+1,R,k-cnt);
}
void dfs1(int x){
	siz[x]=1;dep[x]=dep[pa[x]]+1;
	for(int i=head[x];i;i=e[i].nxt){
		int j=e[i].to;
		if(j==pa[x])continue;
		pa[j]=x;
		dfs1(j);siz[x]+=siz[j];
		if(siz[j]>siz[son[x]])son[x]=j;
	}
}
void dfs2(int u,int t){
	top[u]=t;
	if(!son[u])return;
	dfs2(son[u],t);
	for(int i=head[u];i;i=e[i].nxt){
		int j=e[i].to;
		if(j==pa[u]||j==son[u])continue;
		dfs2(j,j);
	}
}
int LCA(int x,int y){
	while(top[x]!=top[y]){
		if(dep[top[x]]>=dep[top[y]])x=pa[top[x]];
		else y=pa[top[y]];
//		cout<<x<<" "<<y<<endl;
	}
	return dep[x]<dep[y]?x:y;
}
void dfs(int x,int fa){
	rt[x]=change(rt[fa],1,blen,a[x],1);
	for(int i=head[x];i;i=e[i].nxt){
		int j=e[i].to;
		if(j==fa)continue;
		dfs(j,x);
	}
}
signed main(){
//	freopen("P2633_1.in","r",stdin);
//	freopen("my.out","w",stdout);
	n=read(),m=read();
	for(int i=1;i<=n;++i)a[i]=read(),b[i]=a[i];
	sort(b+1,b+n+1);
	blen=unique(b+1,b+n+1)-b-1;
	for(int i=1;i<=n;++i)a[i]=getpos(a[i]);
//	for(int i=1;i<=n;++i)printf("%d ",a[i]);
//	puts("");
	for(int i=1;i<n;++i){
		int u=read(),v=read();
		add(u,v);add(v,u);
	}
	dfs1(1);dfs2(1,1);dfs(1,1);
	//puts("RE!");return 0;
//	for(int i=1;i<=n;++i)printf("%d:dep%d,siz%d\n",i,dep[i],siz[i]);
	for(int i=1;i<=m;++i){
		int u=read(),v=read(),k=read();
		u^=lastans;
//		printf("(%lld %lld)\n",u,v);
		int Lca=LCA(u,v);
//		printf("LCA:%lld\n",Lca);
		lastans=b[query(rt[u],rt[v],rt[Lca],rt[pa[Lca]],1,blen,k)];
		printf("%lld\n",lastans);
	}
	return 0;
}
上一篇:PHP递归


下一篇:let和var的区别,几个小面试题