Educational Codeforces Round 33 (Rated for Div. 2) F - Subtree Minimum Query

F. Subtree Minimum Query
time limit per test6 seconds
memory limit per test512 megabytes
inputstandard input
outputstandard 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)?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.

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

题意:对于一个树,问一个点,他的所有距离他k距离的儿子的最小值,强制在线。
做法:主席树,先把树做成一个线段树,线段树里ll[x]到rr[x]之间的节点代表x和他的所有儿子,然后按照节点的深度构建主席树,查询的时候,对于节点i和深度k,找出深度在1到dep[i]+k的节点构成的主席树,然后查询ll[x]到rr[x]之间的最小值。

#include<bits/stdc++.h>
using namespace std;
struct node{
    int ls,rs,x;
};
const int N = 1e5+100;
node pt[N*40];
vector<int> G[N];
queue<pair<int,int> > que;
int num[N],ll[N],rr[N],root[N],dep[N],pos[N];
bool vis[N];
int n,r,md,tot,Time;
void dfs(int x,int f){
    ll[x] = ++Time;
    int cnt = 1;
    for(int i = 0;i < G[x].size();i ++){
        int v = G[x][i];
        if(v == f) continue;
        dfs(v,x);
    }
    rr[x] = Time;
}
int newnode(){
    int rt = tot++;
    pt[rt].x = 0;
    pt[rt].ls = 0;
    pt[rt].rs = 0;
    return rt;
}
void build(int &rt,int l,int r){
    rt = newnode();
    if(l == r){
        pt[rt].x = 1e9+100;
        return ;
    }
    int mid = l+r>>1;
    build(pt[rt].ls,l,mid);
    build(pt[rt].rs,mid+1,r);
    pt[rt].x = min(pt[pt[rt].ls].x,pt[pt[rt].rs].x);
}
void update(int &rt,int bef,int x,int d,int l,int r){
    rt = newnode();
    if(l == r){
        pt[rt].x = d;
        return ;
    }
    int mid = l+r>>1;
    if(mid >= x){
        pt[rt].rs = pt[bef].rs;
        update(pt[rt].ls,pt[bef].ls,x,d,l,mid);
    }
    else{
        pt[rt].ls = pt[bef].ls;
        update(pt[rt].rs,pt[bef].rs,x,d,mid+1,r);
    }
    pt[rt].x = min(pt[pt[rt].ls].x,pt[pt[rt].rs].x);
}
void solve(int id,int x,int d){
    dep[x] = d;
    pos[d] = id;
    md = max(md,d);
    update(root[id],root[id-1],ll[x],num[x],1,n);
}
int query(int rt,int L,int R,int l,int r){
    if(L <= l && R >= r){
        return pt[rt].x;
    }
    int mid = l+r>>1;
    int ret = 1e9+100;
    if(mid >= L) ret = query(pt[rt].ls,L,R,l,mid);
    if(mid < R) ret = min(query(pt[rt].rs,L,R,mid+1,r),ret);
    return ret;
}
int main(){
    cin >> n >> r;
    for(int i= 1;i<= n;i ++) scanf("%d",&num[i]);
    for(int i =1;i < n;i ++){
        int u,v;
        scanf("%d %d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(r,-1);
    que.push({r,1});
    int cns = 1;
    build(root[0],1,n);
    vis[r] = true;
    while(!que.empty()){
        pair<int,int> now = que.front();
        que.pop();
        solve(cns++,now.first,now.second);
        for(int i = 0;i < G[now.first].size();i ++){
            int v = G[now.first][i];
            if(vis[v]) continue;
            vis[v] = true;
            que.push({v,now.second+1});
        }
    }
    int m;
    cin >> m;
    int last = 0;
    for(int i =1;i <= m;i ++){
        int qi,qk;
        scanf("%d %d",&qi,&qk);
        qi = (last + qi)%n+1;
        qk = (last + qk)%n;
        //cout << qi << ' '<< qk <<"!!" << endl;
        int rt = dep[qi]+qk;
        rt = min(rt,md);
        //cout << qi << ' '<< qk << ' '<<dep[pos[rt]] << endl;
        last = query(root[pos[rt]],ll[qi],rr[qi],1,n);
        printf("%d\n",last);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值