SP2939 QTREE5 - Query on a tree V解题报告:
题意
给定一棵 \(n\) 各点原始全白的树,\(m\) 次操作,支持单点颜色翻转以及查询一个点距离最近的黑点的距离。
\(1\leqslant n,m\leqslant 10^5\)。
分析
模拟赛题,好像有哦个简单的点分树写法,不过操作分块也可以轻松解决。(类似 CF342E)
对于修改操作,你直接维护单点的颜色;查询分为两部分:本块之前修改的点(本快操作中一定不存在修改),本块修改过的点、
第一部分可以直接在每个块结束后维护出每个点距离这样的点的最短距离(bfs),第二部分则可以枚举点求距离直接判断。
用了 \(O(n\log n)-O(1)\) 的 lca,时间复杂度 \(O((n+m)\sqrt m)\)。
代码
#include<stdio.h>
#include<math.h>
#include<vector>
#define inf 1000000000
using namespace std;
const int maxn=100005,maxm=200005,maxk=20,maxq=100005;
int n,m,e,S,T,now,qs;
int start[maxn],to[maxm],then[maxm],lg[maxn<<1],ST[maxn<<1][maxk],dep[maxn],in[maxn],bl[maxn],br[maxn],opt[maxq],k[maxq],dis[maxn],q[maxn],col[maxn],ok[maxn];
inline int calc(int a,int b){
return dep[a]<dep[b]? a:b;
}
inline void add(int x,int y){
then[++e]=start[x],start[x]=e,to[e]=y;
}
void dfs(int x,int last){
dep[x]=dep[last]+1,in[x]=++qs,ST[qs][0]=x;
for(int i=start[x];i;i=then[i]){
int y=to[i];
if(y==last)
continue;
dfs(y,x);
ST[++qs][0]=x;
}
}
void getST(){
lg[0]=-1;
for(int i=1;i<=qs;i++)
lg[i]=lg[i/2]+1;
for(int i=1;i<=18;i++)
for(int j=1;j+(1<<i)-1<=qs;j++)
ST[j][i]=calc(ST[j][i-1],ST[j+(1<<(i-1))][i-1]);
}
int lca(int a,int b){
if(in[a]>in[b])
swap(a,b);
int l=in[a],r=in[b],k=lg[r-l+1];
return calc(ST[l][k],ST[r-(1<<k)+1][k]);
}
int getdis(int a,int b){
return dep[a]+dep[b]-2*dep[lca(a,b)];
}
void bfs(int a,int b,int c,int d){
int hd=1,tl=0;
if(c)
for(int i=c;i<=d;i++)
if(opt[i]==1)
ok[k[i]]=1;
for(int i=1;i<=n;i++){
if(col[i]==1&&ok[i]==0)
q[++tl]=i,dis[i]=0;
else dis[i]=inf;
ok[i]=0;
}
while(hd<=tl){
int x=q[hd++];
for(int i=start[x];i;i=then[i])
if(dis[to[i]]>dis[x]+1)
dis[to[i]]=dis[x]+1,q[++tl]=to[i];
}
}
int query(int x,int a,int b,int c){
int res=dis[x];
if(col[x])
res=0;
for(int i=a;i<=c;i++)
if(opt[i]==1&&col[k[i]]==1)
res=min(res,getdis(x,k[i]));
return res==inf? -1:res;
}
void read(int &x){
char c=getchar();
x=0;
for(;c<'0'||c>'9';c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=x*10+c-48;
}
int main(){
read(n);
for(int i=1,x,y;i<n;i++)
read(x),read(y),add(x,y),add(y,x);
read(m);
dfs(1,0),getST(),S=800,T=m/S;
for(int i=1;i<=T;i++)
bl[i]=br[i-1]+1,br[i]=i*S;
if(br[T]<m)
T++,bl[T]=bl[T-1]+1,br[T]=m;
for(int i=1;i<=n;i++)
dis[i]=inf;
for(int i=1;i<=m;i++)
read(opt[i]),read(k[i]),opt[i]++;
for(int i=1,lst=1;i<=m;i++){
if(i>br[lst])
bfs(bl[lst],br[lst],bl[lst+1],br[lst+1]),lst++;
if(opt[i]==1)
col[k[i]]^=1;
if(opt[i]==2)
printf("%d\n",query(k[i],bl[lst],i,br[lst]));
}
return 0;
}