[cf contest 893(edu round 33)] F - Subtree Minimum Query

[cf contest 893(edu round 33)] F - Subtree Minimum Query

time limit per test
6 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

You are given a rooted tree consisting of n vertices. Each vertex has a number written on it; number 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 a1, a2, ..., an (1 ≤ ai ≤ 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 ≤ 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) modn) + 1, and ki = (qi + last) modn.

Output

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

Example
input
5 2
1 3 2 3 5
2 3
5 1
3 4
4 1
2
1 2
2 3
output
2
5

我们对于树上的每一个节点开一个线段树(其实是可持久化的)。

每棵线段树都是一个[1..maxdepth]的按照绝对深度来建的线段树。

那么,对于每一个节点x,可以把所以它的子节点的线段树合并到它上面去。

但是这需要可持久化。因为当前节点的信息也要用到。如果不可持久化,可能会导致当前节点的地址在其他线段树里面存在。

实际上,每个地址只存在与一棵线段树中。

然后,由于父子节点之间的线段树只有1条链不同,所以要新建logn个节点。

总共有n-1对父子关系,所以空间为O(nlogn)。

时间复杂度为O(mlogn)。注意强制在线。

code:

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 typedef long long LL;
  5 using namespace std;
  6 
  7 void OJ() {
  8     #ifndef ONLINE_JUDGE
  9         freopen("in.txt","r",stdin);
 10         freopen("out.txt","w",stdout);
 11     #endif
 12 }
 13 
 14 namespace fastIO {
 15     #define gec(c) getchar(c)
 16     #define puc(c) putchar(c)
 17     char ch;
 18     inline int read() {
 19         int x=0,f=1; ch=getchar();
 20         while (ch<'0'||ch>'9') {
 21             if (ch=='-') f=-f;
 22             ch=gec();
 23         }
 24         while (ch>='0'&&ch<='9') {
 25             x=(x<<3)+(x<<1)+(ch^48);
 26             ch=gec();
 27         }
 28         return x*f;
 29     }
 30     int ttt,nnn[20];
 31     template <class T> inline void write(T x) {
 32         if (x==0) {
 33             puc('0'); return;
 34         }
 35         if (x<0) x=-x,puc('-');
 36         for (ttt=0; x; x/=10) nnn[++ttt]=x%10;
 37         for (; ttt; --ttt) puc(nnn[ttt]+48);
 38     }
 39     inline void newline () {
 40         puc('\n');
 41     }
 42 } using namespace fastIO;
 43 
 44 const int N=100005,inf=2e9;
 45 int n,q,tot,lim;
 46 int a[N],lnk[N],nxt[N<<1],son[N<<1],dep[N];
 47 struct node {
 48     node* l,* r;
 49     int v;
 50     node () {
 51         l=r=0;
 52         v=inf;
 53     }
 54 } *ro[N];
 55 #define M ((l)+(r)>>1)
 56 inline void refresh (node* c) {
 57     c->v=inf;
 58     if (c->l) c->v=min(c->v,c->l->v);
 59     if (c->r) c->v=min(c->v,c->r->v);
 60 }
 61 inline void setup (node* &c,int l,int r,int x,int v) {
 62     c=new node();
 63     if (l==r) {
 64         c->v=v;
 65         return;
 66     }
 67     if (x<=M) setup(c->l,l,M,x,v);
 68     else setup(c->r,M+1,r,x,v);
 69     refresh(c);
 70 }
 71 inline node* merge (node* x,node* y) {
 72     if (!x||!y) return x?x:y;
 73     node* ret=new node();
 74     ret->l=merge(x->l,y->l);
 75     ret->r=merge(x->r,y->r);
 76     ret->v=min(x->v,y->v);
 77     return ret;
 78 }
 79 inline int reply (node* u,int l,int r,int x,int y) {
 80     if (!u) return inf;
 81     if (x<=l&&r<=y) return u->v;
 82     if (y<=M) return reply(u->l,l,M,x,y); else
 83     if (x>M) return reply(u->r,M+1,r,x,y); else
 84     return min(reply(u->l,l,M,x,y),reply(u->r,M+1,r,x,y));
 85 }
 86 void add (int x,int y) {
 87     nxt[++tot]=lnk[x],lnk[x]=tot,son[tot]=y;
 88 }
 89 void dfs (int x,int p) {
 90     setup(ro[x],1,n,dep[x]=dep[p]+1,a[x]);
 91     lim=max(lim,dep[x]);
 92     for (int j=lnk[x]; j; j=nxt[j]) {
 93         if (son[j]==p) continue;
 94         dfs(son[j],x);
 95         ro[x]=merge(ro[x],ro[son[j]]);
 96     }
 97 }
 98 int main() {
 99     OJ(); int x,y,rot,ans=0;
100     n=read(),rot=read();
101     for (int i=1; i<=n; ++i) {
102         a[i]=read(),ro[i]=0;
103     }
104     for (int i=1; i<n; ++i) {
105         x=read(),y=read();
106         add(x,y),add(y,x);
107     }
108     dep[0]=lim=0,dfs(rot,0);
109     q=read();
110     for ( ; q; --q) {
111         x=read(),y=read();
112         x=(x+ans)%n+1,y=(y+ans)%n;
113         ans=reply(ro[x],1,n,dep[x],min(lim,dep[x]+y));
114         write(ans),newline();
115     }
116     return 0;
117 }
View Code

转载于:https://www.cnblogs.com/whc200305/p/7989259.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值