CF1017G The Tree
题意:给定一棵树,维护以下3个操作:
- 1 \(x\)表示如果节点\(x\)为白色,则将其染黑。否则对这个节点的所有儿子递归进行相同操作
- 2 \(x\)表示将以节点\(x\)为root的子树染白。
- 3 \(x\)表示查询节点\(x\)的颜色。
\(n,q \leq 10^5\)。
题解:考虑一种优雅的暴力------将所有询问分块。真是涨姿势了
由于所有操作都是针对单点的,我们可以在一个块的操作中只考虑这些询问涉及到的点,这样复杂度就降到了块长级别。然后做完后再\(O(n)\)的考虑对原树中其他节点的影响。将块长设为\(\sqrt q\),那么总复杂度就是\(O(n\sqrt n)\)的。
具体来说,我们先建出虚树,注意对每条边存一下边长和这条边上黑点的个数。然后对于1操作,直接暴力做就行,如果当前这条边上所有点都是黑的,就往下递归就行。对于2操作,暴力清空即可。3操作就直接输出,没啥好说的。
在还原这些操作对原树的节点的影响时,我们需要在上述操作中对虚树上的每个点记录两个值:\(cnt_i,sn_i\)分别表示当前节点1操作做了几次对它有影响,当前节点在这些操作中是否是2操作的点的子树里的一个点。DFS一遍就行了。
还有一种树剖的做法,大概是考虑每个\(x\)的祖先\(y\)对它能否造成贡献,把式子搞出来,然后提取出只与\(y\)相关的部分,用线段树维护即可。注意2操作时不仅要将子树清空,还要考虑祖先节点不能对其造成贡献。时间复杂度是俩log。
代码:
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
template<class D>I read(D &res){
res=0;register D g=1;register char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
int n,m,fa[101000],t[101000],v[101000],dfn[101000],dep[101000],siz[101000],id[101000],_tot,lg[202000],xu[202000],f[202000][20],cnt;
int len,b[101000],sum,ori[101000],clr[101000],sn[101000],ct[101000];
inline bool bbb(int x,int y){return dfn[x]<dfn[y];}
IN ckmin(int x,int y){return dep[x]<dep[y]?x:y;}
I print(int x){
if(x)puts("black");
else puts("white");
}
IN ques_lca(int x,int y){
x=id[x];y=id[y];if(x>y)swap(x,y);
re len=lg[y-x+1];return ckmin(f[x][len],f[y-(1<<len)+1][len]);
}
IN getit(int x,int tar){
re res=0;
while(x^tar)res+=clr[x],x=fa[x];
// cout<<x<<" "<<tar<<endl,STS;
return res;
}
namespace VT{
struct E{
int to,nt,s,v;
E(int _to=0,int _nt=0,int _s=0,int _v=0){to=_to;nt=_nt;s=_s;v=_v;}
}e[202000];
#define T e[k].to
int st[101000],q;
int head[101000],tot;
int a[101000],vis[101000],N;
int c[101000],num,las;
I add(int x,int y){
// cout<<"A"<<x<<" "<<y<<endl;
re s=dep[y]-dep[x]-1,v=getit(fa[y],x);
e[++tot].to=y;e[tot].nt=head[x];head[x]=tot;e[tot].s=s;e[tot].v=v;
}
I insert(int x){
if(!q)return st[q=1]=x,void();
re lca=ques_lca(st[q],x);
// cout<<"L"<<lca<<endl;
if(lca==st[q])return st[++q]=x,void();
while(dfn[lca]<dfn[st[q-1]])add(st[q-1],st[q]),q--;
// cout<<"#";
if(st[q-1]==lca)return add(st[q-1],st[q]),q--,st[++q]=x,void();
add(lca,st[q]),q--,st[++q]=lca,st[++q]=x,vis[lca]=1;
}
I build(){
tot=q=0;
if(!vis[1])vis[1]=1,a[++N]=1;
sort(a+1,a+1+N,bbb);
// F(i,1,N)cout<<a[i]<<" ";cout<<endl;
F(i,1,N)insert(a[i]);
// cout<<"!";cout<<endl;
while(q>1)add(st[q-1],st[q]),q--;
F(i,1,n)ori[i]=clr[i];
}
I sign(int x){
// cout<<"%"<<x<<endl;
if(!clr[x])return clr[x]=1,void();
ct[x]++;
for(re k=head[x];k!=-1;k=e[k].nt){
if(e[k].v==e[k].s)sign(T);
else e[k].v++;
}
}
I fill(int x){
clr[x]=ct[x]=0;sn[x]=1;
for(re k=head[x];k!=-1;k=e[k].nt)e[k].v=0,fill(T);
}
I split(int x,int y){
num=dep[y]-dep[x]-1;y=fa[y];
FOR(i,num,1)c[i]=y,y=fa[y];
}
I clear(){
F(i,1,n)head[i]=-1,sn[i]=vis[i]=ct[i]=0;
N=tot=0;
}
};
vector<int>e[101000];
I D_1(int x,int depth){
dfn[x]=++_tot;xu[++cnt]=x;id[x]=cnt;siz[x]=1;dep[x]=depth;
// cout<<x<<" ";
for(auto d:e[x]){
D_1(d,depth+1);siz[x]+=siz[d];xu[++cnt]=x;
}
}
I reform(int x,int S){
// cout<<"$"<<x<<" "<<sum+ct[x]<<endl;
if(VT::vis[x])S=ct[x];
else{
if(sn[x])clr[x]=0;
if(!clr[x]&&S)S--,clr[x]=1;
}
/*if(sn[x]){
for(re k=head[x];k!=-1;k=e[k].nt){
// split(x,T);
// F(i,1,e[k].v)clr[c[i]]=1;
// F(i,e[k].v+1,num)clr[c[i]]=0;
sn[T]=1;reform(T);
}
}
else{
for(re k=head[x];k!=-1;k=e[k].nt){
// split(x,T);las=getit(fa[T],x);
// for(re i=1,j=1;i<=num&&j+las<=e[k].v;i++){
// if(!clr[c[i]])clr[c[i]]=1,j++;
// }
reform(T);
}
}*/
for(auto d:e[x]){
sn[d]|=sn[x];reform(d,S);
}
}
I solve(int l,int r){
// cout<<"!"<<l<<" "<<r<<endl;
F(i,l,r)if(!VT::vis[v[i]])VT::vis[v[i]]=1,VT::a[++VT::N]=v[i];
VT::build();
// cout<<"F"<<endl;
F(i,l,r){
if(t[i]==1){
// ct[v[i]]++;
VT::sign(v[i]);
}
if(t[i]==2)VT::fill(v[i]);
if(t[i]==3)print(clr[v[i]]);
}
// cout<<"@";
// F(i,1,n)cout<<ct[i]<<" ";cout<<endl;
// F(i,1,n)cout<<VT::vis[i];cout<<endl;
// F(i,1,n)clr[i]=ori[i];
reform(1,0);VT::clear();
// F(i,1,n)cout<<clr[i];cout<<endl;
// cout<<"#"<<endl;
}
int main(){
read(n);read(m);C(VT::head,-1);
F(i,2,n)read(fa[i]),e[fa[i]].emplace_back(i);
F(i,1,m)read(t[i]),read(v[i]);
len=ceil(sqrt(m)+0.5);F(i,1,m)b[i]=((i-1)/len)+1;sum=b[m];
D_1(1,0);
//cout<<endl;
lg[0]=-1;F(i,1,cnt)f[i][0]=xu[i],lg[i]=lg[i>>1]+1;
F(j,1,lg[cnt])F(i,1,cnt-(1<<j)+1)f[i][j]=ckmin(f[i][j-1],f[i+(1<<(j-1))][j-1]);
F(i,1,sum)solve((i-1)*len+1,min(m,i*len));
return 0;
}
/*
8 10
1 2 1 2 5 4 5
1 2
3 2
3 1
1 1
1 1
3 5
3 7
3 4
2 2
3 5
*/