【主席樹】Count on a tree

【描述】
給定一棵N個節點的樹,每個點有一個權值,對於M個詢問(u,v,k),你需要回答u xor lastans和v這兩個節點間第K小的點權。其中lastans是上一個詢問的答案,初始爲0,即第一個詢問的u是明文。
【輸入】
第一行兩個整數N,M。
第二行有N個整數,其中第i個整數表示點i的權值。
後面N-1行每行兩個整數(x,y),表示點x到點y有一條邊。
最後M行每行兩個整數(u,v,k),表示一組詢問
【輸出】
M行,表示每個詢問的答案。最後一個詢問不輸出換行符

【思路】

我們先來考慮序列第k大。我們查詢[l,r]的情況,變成查詢r和l-1。那麼樹上也可以類似操作。我們在每個節點維護其到根節點的信息。路徑上的信息可以通過sizu+sizvsizlca(u,v)sizfa[lca(u,v)]siz_u+siz_v-siz_{lca(u,v)}-siz_{fa[lca(u,v)]}得到。所以我們只需要同時在四個點對應的樹上查詢即可。
代碼:

#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define re register
using namespace std;
const int N=1e5+5;
int n,m,a,b,k,c[N],val[N],tot,rt[N],las;
tr1::unordered_map<int,int>f;
inline int red()
{
    int data=0;int w=1; char ch=0;
    ch=getchar();
    while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0' && ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
    return data*w;
}
namespace tree{
	int ch[N*30|1][2],siz[N*30|1],cnt=0;
	int change(int v,int l,int r,int pos)
	{
		int u=++cnt;siz[u]=siz[v]+1;
		if(l==r)return cnt;
		int mid=(l+r)>>1;
		ch[u][0]=ch[v][0];ch[u][1]=ch[v][1];
		if(pos<=mid)ch[u][0]=change(ch[v][0],l,mid,pos);
		else ch[u][1]=change(ch[v][1],mid+1,r,pos);
		return u;
	}
	int query(int a,int b,int c,int d,int l,int r,int k)
	{
		if(l==r)return l;
		int ls=siz[ch[a][0]]+siz[ch[b][0]]-siz[ch[c][0]]-siz[ch[d][0]];
		int mid=(l+r)>>1;
		if(ls>=k)return query(ch[a][0],ch[b][0],ch[c][0],ch[d][0],l,mid,k);
		else return query(ch[a][1],ch[b][1],ch[c][1],ch[d][1],mid+1,r,k-ls);
	}
}
using tree::change;
using tree::query;
namespace LCA{
	vector<int>g[N];
	int dep[N]={0,1},fa[N][18];
	void dfs(int u){
		rt[u]=change(rt[fa[u][0]],1,tot,f[val[u]]);
		for(int re i=1;(1<<i)<=(dep[u]);i++)fa[u][i]=fa[fa[u][i-1]][i-1];
		for(int re i=g[u].size()-1;~i;--i){int v=g[u][i];if(!dep[v])dep[v]=dep[u]+1,fa[v][0]=u,dfs(v);}
	}
	inline int lca(int a,int b)
	{
		if(dep[a]<dep[b])swap(a,b);
		int t=dep[a]-dep[b];
		for(int re i=0;(1<<i)<=t;++i)
			if(t&(1<<i))a=fa[a][i];
		if(a==b)return a;
		for(int re i=17;~i;--i)
			if(fa[a][i]!=fa[b][i])a=fa[a][i],b=fa[b][i];
		return fa[a][0];
	}
}
using LCA::g;
using LCA::dfs;
using LCA::lca;
int main()
{
	n=red();m=red();
	for(int re i=1;i<=n;i++)c[i]=val[i]=red();
	sort(c+1,c+(tot=n)+1);tot=unique(c+1,c+n+1)-c-1;
	for(int re i=1;i<=tot;i++)f[c[i]]=i;
	for(int re i=1;i^n;i++)a=red(),b=red(),g[a].push_back(b),g[b].push_back(a);dfs(1);
	while(m--){
		a=red()^las;b=red();k=red();int lc1=lca(a,b),lc2=LCA::fa[lc1][0];
		printf("%d",las=c[query(rt[a],rt[b],rt[lc1],rt[lc2],1,tot,k)]);if(m)putchar('\n');
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章