CF825G Tree Queries
洛谷CF825G Tree Queries
一棵树有 n n n个节点,初始时均为白色,有两种操作:
1 x
表示把结点 x x x染成黑色1 x
表示查询 x x x到树上任意一个黑色结点的简单路径上的编号最小的结点的编号本题强制在线。输入 t p tp tp和 z z z,其中 t p tp tp表示操作类型, x = ( z + l a s t ) m o d n + 1 x=(z+last)\bmod n+1 x=(z+last)modn+1,其中 l a s t last last为上一次询问的答案,初始时 l a s t = 0 last=0 last=0。
保证第一次操作为操作 1 1 1。
1 ≤ n , q ≤ 1 0 6 1\leq n,q\leq 10^6 1≤n,q≤106
我们把第一个染成黑色的点 t t t设为根,设查询的点为 x x x,某个被染成黑色的点为 y y y。
则 a n s = min y { d i s ( x , y ) } ans=\min\limits_y\{dis(x,y)\} ans=ymin{dis(x,y)},其中 d i s ( x , y ) dis(x,y) dis(x,y)表示 x → y x\to y x→y路径上编号最小的点。
设 x x x和 y y y的 l c a lca lca为 z z z,则 d i s ( x , y ) = min ( d i s ( x , z ) , d i s ( z , y ) ) dis(x,y)=\min(dis(x,z),dis(z,y)) dis(x,y)=min(dis(x,z),dis(z,y))。
那么 a n s = min y { min ( d i s ( x , z ) , d i s ( z , y ) ) } ans=\min\limits_y\{\min(dis(x,z),dis(z,y))\} ans=ymin{min(dis(x,z),dis(z,y))}。
因为 d i s ( t , x ) ≤ d i s ( x , z ) dis(t,x)\leq dis(x,z) dis(t,x)≤dis(x,z),所以 d i s ( x , z ) dis(x,z) dis(x,z)肯定会被 d i x ( t , x ) dix(t,x) dix(t,x)覆盖,那么 a n s = min ( d i s ( t , x ) , min y { d i s ( z , y ) } ) ans=\min(dis(t,x),\min\limits_y\{dis(z,y)\}) ans=min(dis(t,x),ymin{dis(z,y)})。
我们继续推式子。 min ( d i s ( t , x ) , d i s ( z , y ) ) = min ( d i s ( t , z ) , d i s ( z , x ) , d i s ( z , y ) ) = min ( d i s ( t , x ) , d i s ( t , y ) ) \min(dis(t,x),dis(z,y))=\min(dis(t,z),dis(z,x),dis(z,y))=\min(dis(t,x),dis(t,y)) min(dis(t,x),dis(z,y))=min(dis(t,z),dis(z,x),dis(z,y))=min(dis(t,x),dis(t,y)),所以 a n s = min ( d i s ( t , x ) , min y { d i s ( t , y ) } ) ans=\min(dis(t,x),\min\limits_y\{dis(t,y)\}) ans=min(dis(t,x),ymin{dis(t,y)})。
也就是说,我们只需要用 d f s dfs dfs求出 t t t到每个点 x x x的 d i s ( t , x ) dis(t,x) dis(t,x),然后维护 min y { d i s ( t , y ) } \min\limits_y\{dis(t,y)\} ymin{dis(t,y)}即可。
时间复杂度为 O ( n + q ) O(n+q) O(n+q)。
#include
using namespace std;
const int N=1000000;
int n,q,rt,tmp,ans,tot=0,d[2*N+5],l[2*N+5],r[N+5],dis[N+5];
void add(int xx,int yy){
l[++tot]=r[xx];d[tot]=yy;r[xx]=tot;
}
void dfs(int u,int fa){
for(int i=r[u];i;i=l[i]){
if(d[i]==fa) continue;
dis[d[i]]=min(dis[u],d[i]);
dfs(d[i],u);
}
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1,x,y;i<n;i++){
scanf("%d%d",&x,&y);
add(x,y);add(y,x);
}
scanf("%*d%d",&rt);--q;
tmp=rt=(rt+ans)%n+1;
dis[rt]=rt;dfs(rt,0);
for(int i=1,tp,x;i<=q;i++){
scanf("%d%d",&tp,&x);
x=(x+ans)%n+1;
if(tp==1) tmp=min(tmp,dis[x]);
else printf("%d\n",ans=min(tmp,dis[x]));
}
return 0;
}