Codeforces - Subtree Minimum Query

题目链接:Codeforces - Subtree Minimum Query


容易想到,我们按照深度插入权值,用主席树合并答案。

但是主席树无法维护最值,故使用线段树合并即可。

因为要存每个子树的信息,所以合并的时候需要新开节点。

每次查询的时候,只查询深度dep[x]到dep[x]+k即可。


AC代码:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e5+10;
int n,m,a[N],r,dep[N],res;
int rt[N],mi[N*40],lc[N*40],rc[N*40],cnt;
vector<int> g[N];
inline void add(int a,int b){g[a].push_back(b),g[b].push_back(a);}
void change(int &p,int l,int r,int x,int val){
	if(!p)	p=++cnt;
	if(l==r){mi[p]=val;	return ;}
	int mid=l+r>>1;
	if(x<=mid)	change(lc[p],l,mid,x,val);
	else	change(rc[p],mid+1,r,x,val);
	mi[p]=min(mi[lc[p]],mi[rc[p]]);
}
int ask(int p,int l,int r,int ql,int qr){
	if(!p)	return 0x3f3f3f3f;
	if(l==ql&&r==qr)	return mi[p];
	int mid=l+r>>1;
	if(qr<=mid)	return ask(lc[p],l,mid,ql,qr);
	else if(ql>mid)	return ask(rc[p],mid+1,r,ql,qr);
	else	return min(ask(lc[p],l,mid,ql,mid),ask(rc[p],mid+1,r,mid+1,qr));
}
int merge(int x,int y,int l,int r){
	if(!x||!y)	return x+y;
	int mid=l+r>>1;
	if(l==r){mi[++cnt]=min(mi[x],mi[y]);	return cnt;}
	int p=++cnt;
	lc[p]=merge(lc[x],lc[y],l,mid);
	rc[p]=merge(rc[x],rc[y],mid+1,r);
	mi[p]=min(mi[lc[p]],mi[rc[p]]);
	return p;
}
void dfs(int x,int fa){
	dep[x]=dep[fa]+1;	change(rt[x],1,n,dep[x],a[x]);
	for(auto to:g[x])	if(to!=fa){
		dfs(to,x);	rt[x]=merge(rt[x],rt[to],1,n);
	}
}
signed main(){
	cin>>n>>r;	memset(mi,0x3f,sizeof mi);
	for(int i=1;i<=n;i++)	scanf("%d",&a[i]);
	for(int i=1,a,b;i<n;i++)	scanf("%d %d",&a,&b),add(a,b);
	dfs(r,r);	cin>>m;
	while(m--){
		int x,k;	scanf("%d %d",&x,&k);
		x=(x+res)%n+1,k=(k+res)%n;
		printf("%d\n",res=ask(rt[x],1,n,dep[x],min(dep[x]+k,n)));
	}
	return 0;
}
发布了553 篇原创文章 · 获赞 242 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_43826249/article/details/104185582