【Codeforces 893F】Subtree Minimum Query

【题目】

传送门

Description

You are given a rooted tree consisting of n vertices. Each vertex has a number written on it; number a i a_i ai is written on vertex i.

Let’s denote d(i, j) as the distance between vertices i and j in the tree (that is, the number of edges in the shortest path from i to j). Also let’s denote the k-blocked subtree of vertex x as the set of vertices y such that both these conditions are met:

  • x is an ancestor of y (every vertex is an ancestor of itself);
  • d(x, y) ≤ k.

You are given m queries to the tree. i-th query is represented by two numbers xi and ki, and the answer to this query is the minimum value of aj among such vertices j such that j belongs to ki-blocked subtree of xi.

Write a program that would process these queries quickly!

Note that the queries are given in a modified way.

Input

The first line contains two integers n and r (1 ≤ r ≤ n ≤ 100000) — the number of vertices in the tree and the index of the root, respectively.

The second line contains n integers a 1 a_1 a1,  a 2 a_2 a2, …,  a n a_n an (1 ≤  a i a_i ai ≤  1 0 9 10^9 109) — the numbers written on the vertices.

Then n - 1 lines follow, each containing two integers x and y (1 ≤ x, y ≤ n) and representing an edge between vertices x and y. It is guaranteed that these edges form a tree.

Next line contains one integer m (1 ≤ m ≤  1 0 6 10^6 106) — the number of queries to process.

Then m lines follow, i-th line containing two numbers pi and qi, which can be used to restore i-th query (1 ≤ pi, qi ≤ n).

i-th query can be restored as follows:

Let last be the answer for previous query (or 0 if i = 1). Then xi = ((pi + last) mod n) + 1, and ki = (qi + last) mod n.

Output

Print m integers. i-th of them has to be equal to the answer to i-th query.

Sample Input

5 2
1 3 2 3 5
2 3
5 1
3 4
4 1
2
1 2
2 3

Sample Output

2
5


【分析】

题目大意:给出一颗有根树,每个节点都有权值,边权都是 1 1 1,给出 q q q 个询问,表示询问在以 x x x 为根的子树中,与 x x x 相距不超过 k k k 的所有点中的点权最小值,强制在线

算是一道比较好的题了吧

还是先对这棵树的每个点都单独建一颗权值线段树(以深度为下标),对于线段树的每个节点,都统计这个区间里的最小值,在 d f s dfs dfs 的时候向上合并

然后对于询问,直接查询 d e p x dep_x depx d e p x + k dep_x+k depx+k 这段区间里的最小值就可以了


【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
using namespace std;
int n,m,r,t,tot,depth;
int first[N],v[N<<1],nxt[N<<1];
int a[N],dep[N],root[N],Min[N<<6],lc[N<<6],rc[N<<6];
void add(int x,int y)
{
	t++;
	nxt[t]=first[x];
	first[x]=t;
	v[t]=y;
}
void dfs(int x,int father)
{
	int i,k;
	depth=max(depth,dep[x]);
	for(i=first[x];i;i=nxt[i])
	{
		k=v[i];
		if(k!=father)
		{
			dep[k]=dep[x]+1;
			dfs(k,x);
		}
	}
}
void insert(int &root,int l,int r,int pos,int num)
{
	root=++tot;
	Min[root]=num;
	if(l==r)  return;
	int mid=(l+r)>>1;
	if(pos<=mid)  insert(lc[root],l,mid,pos,num);
	else  insert(rc[root],mid+1,r,pos,num);
}
int Merge(int x,int y,int l,int r)
{
	if(!x||!y)  return x+y;
	int now=++tot;
	Min[now]=min(Min[x],Min[y]);
	int mid=(l+r)>>1;
	if(l==r)  return now;
	lc[now]=Merge(lc[x],lc[y],l,mid);
	rc[now]=Merge(rc[x],rc[y],mid+1,r);
	return now;
}
void Dfs(int x,int father)
{
	int i,k;
	insert(root[x],1,depth,dep[x],a[x]);
	for(i=first[x];i;i=nxt[i])
	{
		k=v[i];
		if(k!=father)
		{
			Dfs(k,x);
			root[x]=Merge(root[x],root[k],1,depth);
		}
	}
}
int query(int root,int l,int r,int x,int y)
{
	if(!root)  return 0x3f3f3f3f;
	if(l>=x&&r<=y)  return Min[root];
	int mid=(l+r)>>1;
	if(y<=mid)  return query(lc[root],l,mid,x,y);
	if(x>mid)  return query(rc[root],mid+1,r,x,y);
	return min(query(lc[root],l,mid,x,y),query(rc[root],mid+1,r,x,y));
}
int main()
{
	int x,y,i,ans=0;
	scanf("%d%d",&n,&r);
	for(i=1;i<=n;++i)
	  scanf("%d",&a[i]);
	for(i=1;i<n;++i)
	{
		scanf("%d%d",&x,&y);
		add(x,y),add(y,x);
	}
	dep[r]=1;
	dfs(r,0),Dfs(r,0);
	scanf("%d",&m);
	for(i=1;i<=m;++i)
	{
		scanf("%d%d",&x,&y);
		x=(x+ans)%n+1,y=(y+ans)%n;
		ans=query(root[x],1,depth,dep[x],min(dep[x]+y,depth));
		printf("%d\n",ans);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值