题目大意:
给定一个$n(nle10^5)$个结点的树,初始全为白点。$m(mle10^5)$次操作,每次将点$x$染成黑色或询问从$x$出发至少经过一个黑点能到达的点中,编号次大的点。
思路:
将操作倒序处理,即原操作变为擦除颜色和询问两种操作。用并查集维护白点连通块和若干单独的黑点。记录每个连通块或黑点出发至少经过一个黑点能到达的点中,能到达的最大和次大的点。擦除黑点时进行合并即可。维护最大、次大点时选择答案较小的连通块暴力递减。递减次数加起来是$n$。初始时每个连通块维护的最大值都是$n$,次大值都是$n-1$。而只有当连通块的点中含有$n$或$n-1$时,答案才会变小。每次合并时从两个连通块中答案比较小的往下枚举,总共最多枚举$2n$次。时间复杂度$O((n+m)alpha(n)$比标算不知道高到哪里去了。
1 #include<cstdio> 2 #include<cctype> 3 #include<algorithm> 4 inline int getint() { 5 register char ch; 6 while(!isdigit(ch=getchar())); 7 register int x=ch^'0'; 8 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 9 return x; 10 } 11 const int N=1e5+1,M=1e5+1; 12 struct Edge { 13 int to,next; 14 }; 15 Edge e[N<<1]; 16 int h[N],b[N],ans[N]; 17 inline void add_edge(const int &u,const int &v) { 18 e[++h[0]]=(Edge){v,h[u]};h[u]=h[0]; 19 e[++h[0]]=(Edge){u,h[v]};h[v]=h[0]; 20 } 21 std::pair<bool,int> q[M]; 22 struct DisjointSet { 23 int anc[N]; 24 void reset(const int &n) { 25 for(register int i=1;i<=n;i++) anc[i]=i; 26 } 27 int find(const int &x) { 28 return x==anc[x]?x:anc[x]=find(anc[x]); 29 } 30 void merge(const int &x,const int &y) { 31 anc[find(x)]=find(y); 32 } 33 bool same(const int &x,const int &y) { 34 return find(x)==find(y); 35 } 36 }; 37 DisjointSet s; 38 std::pair<int,int> max[N]; 39 inline void maintain(const int &x) { 40 while(max[x].first&&s.same(x,max[x].first)) max[x].first--; 41 max[x].second=std::max(std::min(max[x].second,max[x].first-1),0); 42 while(max[x].second&&s.same(x,max[x].second)) max[x].second--; 43 } 44 int main() { 45 for(register int T=getint();T;T--) { 46 const int n=getint(),m=getint(); 47 std::fill(&h[0],&h[n]+1,-1); 48 for(register int i=1;i<n;i++) { 49 add_edge(getint(),getint()); 50 } 51 for(register int i=1;i<=m;i++) { 52 const bool opt=getint()&1; 53 const int x=getint(); 54 if(opt&&!b[x]) b[x]=i; 55 q[i]={opt,x}; 56 } 57 s.reset(n); 58 std::fill(&max[1],&max[n]+1,std::make_pair(n,n-1)); 59 for(register int i=1;i<=n;i++) { 60 if(!b[i]) maintain(i); 61 } 62 for(register int x=1;x<=n;x++) { 63 if(b[x]) continue; 64 for(register int i=h[x];~i;i=e[i].next) { 65 const int &y=e[i].to; 66 if(b[y]||s.same(x,y)) continue; 67 max[s.find(y)]=std::min(max[s.find(y)],max[s.find(x)]); 68 s.merge(x,y); 69 maintain(s.find(x)); 70 } 71 } 72 for(register int i=m;i;i--) { 73 const bool opt=q[i].first; 74 const int x=q[i].second; 75 if(opt&&b[x]==i) { 76 b[x]=0; 77 maintain(s.find(x)); 78 for(register int i=h[x];~i;i=e[i].next) { 79 const int &y=e[i].to; 80 if(b[y]||s.same(x,y)) continue; 81 max[s.find(y)]=std::min(max[s.find(y)],max[s.find(x)]); 82 s.merge(x,y); 83 maintain(s.find(x)); 84 } 85 } 86 if(!opt) { 87 ans[i]=max[s.find(x)].second?:-1; 88 } 89 } 90 for(register int i=1;i<=m;i++) { 91 if(!q[i].first) printf("%d ",ans[i]); 92 } 93 } 94 return 0; 95 }