题目链接: http://codeforces.com/contest/825/problem/G
题意:
给你一棵树,树上的结点开始全部为白色,现在给你两种操作。
① 1 1 1 x x x 表示将结点 x x x 染成黑色(保证第一次操作一定为类型①)
② 2 2 2 x x x 表示询问从结点 x x x 到任意一个黑色的点的路径上经过的最小结点的下标。
做法:
你会发现如果你染了几个结点,那么这些结点之间的路径上的所有结点的最小值,都可以作为下一次询问任何节点的可能答案。 即如果 P 2 P_2 P2 和 P 3 P_3 P3 都为黑色,那么我询问 P 4 P_4 P4 的时候, P 2 P_2 P2 和 P 3 P_3 P3之间路径上的结点最小值 a n s m i n ans_{min} ansmin 是可能作为答案的,那么另一种可能是什么呢,是 P 4 P_4 P4 本身到某个黑色 P i P_i Pi 的最小下标。
这个我们可以这么来表示呢,其实我们完全可以 以开始给你的第一个染黑的结点为根节点 r o o t root root ,之后每次染色的时候,将被染色结点 x x x 到根节点 r o o t root root的最小值 d p [ x ] dp[x] dp[x]来更新上面提到的 a n s m i n ans_{min} ansmin 。在查询的时候,将被查询结点 u u u 的 d p [ u ] dp[u] dp[u] 和 a n s m i n ans_{min} ansmin 取最小值即可。
为什么可以这样做呢,因为对于任意两个黑色的结点,在到达 r o o t root root 之前不管是否有点相交,都不会对结果造成影响,依旧可以保证 a n s m i n ans_{min} ansmin 是正确的(这个可以画个图自己感受一下),所以正确性是可以证明的。
代码
#include
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define rep_e(i,u) for(int i=head[u];~i;i=nex[i])
using namespace std;
typedef long long ll;
const int maxn=1000005;
const int maxm=2000005;
int n,dp[maxn],vis[maxn],q;
int head[maxn],to[maxm],nex[maxm],cnt;
void add(int u,int v){
to[cnt]=v;nex[cnt]=head[u];
head[u]=cnt++;
}
void dfs(int u,int f){
dp[u]=min(u,dp[f]);
rep_e(i,u){
int v=to[i];
if(v==f) continue;
dfs(v,u);
}
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&q);
rep(i,2,n){
int x,y; scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
int op,x;
scanf("%d%d",&op,&x);
dp[0]=1e9;
x=x%n+1;
dfs(x,0);
int last=0,mi=x;
rep(i,2,q){
scanf("%d%d",&op,&x);
x=(x+last)%n+1;
if(op==1){
mi=min(mi,dp[x]);
}
else{
last=min(mi,dp[x]);
printf("%d\n",last);
}
}
return 0;
}