现在有 \(n\) 次操作,每次将一个点设为黑色,或者查询:从当前点到任意黑点路径上最小值的最小值。保证第一次操作是设置黑点。强制在线。
我们考虑这样一个过程,我们把第一次操作的点设为根,从根出发进行 dfs,找到每个点到根的最小值 \(a_x\)。这样如果不增加新的黑点,查询 \(x\) 点的答案就是 \(a_x\)。
然后考虑加入了新黑点 \(y\),询问 \(x\),我们发现答案就是 \(\min(a_y,a_x)\),因为 \(a_y\) 造成的贡献可以分成两部分 \(y\rightarrow lca(x,y)\) 和 \(lca(x,y)\rightarrow root\)。其中第一部分是从 \(x\) 到 \(y\) 可以经过的,第二部分是 \(x\) 到 \(root\) 可以经过的。
而路径上的点又分成 \(y\rightarrow lca(x,y)\) 和 \(x\rightarrow lca(x,y)\),分别被 \(a_y\) 和 \(a_x\) 包括了。也就做到了不重不漏。
那么,假设当前的黑点点集是 \(S\),答案就是 \(\min(\min_{i\in S}a_i,a_x)\)。
动态记录所有黑点的最小值即可。
int n,a[1000005],q,t,x,ans=0,res,a,b;
vt<int>vv[1000005];
inline void dfs(int x,int p){
a[x]=min(x,a[p]);
for(auto j:vv[x])if(j!=p){
dfs(j,x);
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);a[0]=1e9;
cin>>n>>q;
rp(i,n-1){
cin>>a>>b;
vv[a].pb(b);
vv[b].pb(a);
}
cin>>t>>x;x=(x+0)%n+1;
dfs(x,0);
res=x;
rd(_,q-1){
cin>>t>>x;
x=(x+ans)%n+1;
if(t==1)res=min(res,a[x]);
else {
ans=min(res,a[x]);
cout<<ans<<'\n';
}
}
return 0;
}
//Crayan_r
标签:min,黑点,res,lca,Queries,Tree,cin,dfs,CF825G
From: https://www.cnblogs.com/jucason-xu/p/17149327.html