首页 > 其他分享 >LuoguP2633 Count on a tree

LuoguP2633 Count on a tree

时间:2022-10-13 17:24:31浏览次数:58  
标签:Count cnt val rs tree ll LuoguP2633 fa ls

题意

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

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

对于 \(100\%\) 的数据,\(1\le n,m \le 10^5\)。

题解

树上主席树板子。全程独立码完,感觉主席树的代码应该是没问题了,只是还缺乏一些应用的练习。

众所周知查询第 k 小的主席树本质上是个前缀和。

众所周知这个世界上有个叫树上前缀和的东西。

众所周知常规的树上前缀和的式子是 \(dis_{u,v}=sum_u+sum_v-sum_{lca_{u,v}}-sum_{fa_{lca}}\) 。

然后就做完了。是不是特别容易呢?

const ll maxn=1e5+5;
struct node{
	ll val,ls,rs;
};
ll n;
namespace hjt{
	#define mid ((l+r)>>1)
	node t[maxn*20];
	ll cnt=0;
	ll get(){
		cnt++;
		t[cnt].val=0;
		t[cnt].ls=t[cnt].rs=-1;
		return cnt;
	}
	void upd(ll x){
		t[x].val=0;
		if(t[x].ls>=0)t[x].val+=t[t[x].ls].val;
		if(t[x].rs>=0)t[x].val+=t[t[x].rs].val;
	}
	void build(ll x,ll l,ll r){
		if(l==r){
			return ;
		}
		t[x].ls=get();
		t[x].rs=get();
		build(t[x].ls,l,mid);
		build(t[x].rs,mid+1,r);
	}
	void init(){
		for(ll i=0;i<=n;i++)get();
		//cerr<<cnt<<endl;
		build(0,1,n);
		//cerr<<cnt<<endl;
	}
	void insert(ll u,ll v,ll l,ll r,ll k){
		if(l==r){
			t[v].val++;
			return ;
		}
		if(k<=mid){
			t[v].rs=t[u].rs;
			t[v].ls=get();
			insert(t[u].ls,t[v].ls,l,mid,k);
		}
		else {
			t[v].ls=t[u].ls;
			t[v].rs=get();
			insert(t[u].rs,t[v].rs,mid+1,r,k);
		}
		upd(v);
		// cerr<<u<<" "<<v<<" "<<t[v].val<<endl;
	}
	ll query(ll u,ll v,ll lc,ll fa,ll l,ll r,ll k){
		if(l==r){
			return l;
		}
		if(k<=t[t[u].ls].val+t[t[v].ls].val-t[t[lc].ls].val-t[t[fa].ls].val){
			return query(t[u].ls,t[v].ls,t[lc].ls,t[fa].ls,l,mid,k);
		}
		return query(t[u].rs,t[v].rs,t[lc].rs,t[fa].rs,mid+1,r,k-(t[t[u].ls].val+t[t[v].ls].val-t[t[lc].ls].val-t[t[fa].ls].val));
	}
	#undef mid
}
ll a[maxn],b[maxn],tot;
vector<ll>e[maxn];
namespace lca{
	ll fa[maxn][20],dep[maxn];
	void dfs(ll x){
		dep[x]=dep[fa[x][0]]+1;
		hjt::insert(fa[x][0],x,1,n,a[x]);
		// cerr<<fa[x][0]<<" "<<x<<" "<<a[x]<<endl;
		//cerr<<x<<" "<<hjt::t[x].val<<" "<<hjt::t[fa[x][0]].val<<endl;
		for(ll i=1;i<=17;i++){
			fa[x][i]=fa[fa[x][i-1]][i-1];
			if(!fa[x][i])break;
		}
		for(auto v:e[x]){
			if(v==fa[x][0])continue;
			fa[v][0]=x;
			dfs(v);
		}
	}
	ll query(ll u,ll v){
		if(dep[u]<dep[v])swap(u,v);
		for(ll i=17;i>=0;i--){
			if(dep[fa[u][i]]>=dep[v])u=fa[u][i];
		}
		if(u==v)return u;
		for(ll i=17;i>=0;i--){
			if(fa[u][i]!=fa[v][i])u=fa[u][i],v=fa[v][i];
		}
		return fa[u][0];
	}
}
ll m,lst;
void solve(){
	n=R,m=R;
	for(ll i=1;i<=n;i++){
		a[i]=b[i]=R;
	}
	sort(b+1,b+1+n);
	tot=unique(b+1,b+1+n)-b-1;
	for(ll i=1;i<=n;i++){
		a[i]=lower_bound(b+1,b+1+tot,a[i])-b;
		//cerr<<a[i]<<endl;
	}
	hjt::init();
	for(ll i=1;i<n;i++){
		ll u=R,v=R;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	lca::dfs(1);
	for(ll i=0;i<=n;i++){
	//	cerr<<i<<" "<<lca::fa[i][0]<<" "<<hjt::t[i].val<<endl;
		//cerr<<lca::fa[i][0]<<endl;
	}
	while(m--){
		ll u=R,v=R,k=R;
		u^=lst;
		//cerr<<u<<" "<<v<<endl;
		ll lc=lca::query(u,v);
		//cerr<<<<endl;
		lst=b[hjt::query(u,v,lc,lca::fa[lc][0],1,n,k)];
		we(lst);
	}
	return ;
}

标签:Count,cnt,val,rs,tree,ll,LuoguP2633,fa,ls
From: https://www.cnblogs.com/rnfmabj/p/luogup2633.html

相关文章