Educational Codeforces Round 25 G. Tree Queries

time limit per test3 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
You are given a tree consisting of n vertices (numbered from 1 to n). Initially all vertices are white. You have to process q queries of two different types:

1 x — change the color of vertex x to black. It is guaranteed that the first query will be of this type.
2 x — for the vertex x, find the minimum index y such that the vertex with index y belongs to the simple path from x to some black vertex (a simple path never visits any vertex more than once).
For each query of type 2 print the answer to it.

Note that the queries are given in modified way.

Input
The first line contains two numbers n and q (3 ≤ n, q ≤ 106).

Then n - 1 lines follow, each line containing two numbers xi and yi (1 ≤ xi < yi ≤ n) and representing the edge between vertices xi and yi.

It is guaranteed that these edges form a tree.

Then q lines follow. Each line contains two integers ti and zi, where ti is the type of ith query, and zi can be used to restore xi for this query in this way: you have to keep track of the answer to the last query of type 2 (let’s call this answer last, and initially last = 0); then xi = (zi + last) mod n + 1.

It is guaranteed that the first query is of type 1, and there is at least one query of type 2.

Output
For each query of type 2 output the answer to it.

Example
input
4 6
1 2
2 3
3 4
1 2
1 2
2 2
1 3
2 2
2 2
output
3
2
1
题意大概就是给一个树,有两种操作,1:把某个节点涂黑,2:询问这个节点到其他所有黑点的路径上的最小的节点,保证第一个询问是第一种操作。当询问一个节点x的时候,可以特殊化一个黑点,把这个黑点作为根,那么就可以发现,节点x到所有黑点的路径就是所有黑点到根的路径加上节点x到根的路径,所以,把第一个涂黑的点作为根,执行操作1时,就把当前点到根全部涂黑,执行操作2时,答案就是所有黑点的最小值和当前节点到根路径上的最小值的较小值就是答案。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+100;
vector<int> G[N];
int fa[N];
int n,m;
bool vis[N];
int ans[N];
void add_edge(int u,int v){
    G[u].push_back(v);
    G[v].push_back(u);
}
void dfs(int x,int pre){
    vis[x] = true;
    if(pre != -1)
    ans[x] = min(x,ans[pre]);
    fa[x] = pre;
    for(int i= 0;i < G[x].size();i ++){
        int v = G[x][i];
        if(vis[v]) continue;
        dfs(v,x);
    }
}
int main(){
    cin >> n >> m;
    for(int i= 1;i < n;i ++){
        int a,b;
        scanf("%d %d",&a,&b);
        add_edge(a,b);
    }
    int now;
    scanf("%d",&now);
    scanf("%d",&now);
    int root = now%n+1;
    memset(vis,false,sizeof(vis));
    ans[root] = root;
    dfs(root,-1);

    int mn = root;
    int cns = 0;
    for(int i= 1;i < m;i ++){
        int op,x;
        scanf("%d %d",&op,&x);
        if(op == 1){
            x = (x+cns)%n+1;
            mn = min(ans[x],mn);
        }
        else{
            x = (x+cns)%n+1;
            cns = min(ans[x],mn);
            printf("%d\n",cns);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值