傳送門
這題就很妙,第一次看到維護最大後綴和的做法
有三個操作:
- 從一個點往下染黑,是黑色節點就繼續染,一直染到白色節點爲止;
- 染白一棵子樹;
- 查詢一個點的顏色。
對於一個點,狂染黑
染n次,最多對比它深n-1層的點造成影響
不知怎麼就想到:這個節點下面的點對這個節點染色的貢獻爲-1,就像一個最大後綴和
整理一下語言就是對於v和它的祖先u,u染黑n次,u,v之間點對這個染色“弱化”了距離次,如果距離>染黑次數,那麼v沒有被影響到,反之影響到
於是考慮所有點最初權值-1,染黑權值+1,染白權值-1,查詢最大後綴和(線段樹維護),後綴和<0黑,>=0白
#include<bits/stdc++.h>
using namespace std;
#define in Read()
inline int in{
int i=0,f=1;char ch=0;
while(ch!='-'&&!isdigit(ch)) ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int NNN=1e5+5;
const int INF=1e9+7;
int n,q;
int tot;
int ord;
int first[NNN];
int nxt[NNN<<1];
int aim[NNN<<1];
int faz[NNN];
int son[NNN];
int top[NNN];
int siz[NNN];
int dfn[NNN];
int dep[NNN];
struct Tree{
int l,r;
int bmx;//back max
int sum;
int cov;//cover tag
inline void merge(Tree l,Tree r){
sum=l.sum+r.sum;
bmx=max(r.bmx,r.sum+l.bmx);
}
}tre[NNN<<2],ans;
inline void add(int u,int v){
++tot;
nxt[tot]=first[u];
first[u]=tot;
aim[tot]=v;
return;
}
inline void DFS1(int fa,int u){
faz[u]=fa;
siz[u]=1;
dep[u]=dep[fa]+1;
for(int e=first[u];e;e=nxt[e]){
int v=aim[e];
DFS1(u,v);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v]) son[u]=v;
}
return;
}
inline void DFS2(int u,int tp){
top[u]=tp;
dfn[u]=++ord;
if(!son[u]) return;
DFS2(son[u],tp);
for(int e=first[u];e;e=nxt[e]){
int v=aim[e];
if(v==son[u]) continue;
DFS2(v,v);
}
return;
}
#define lch p<<1
#define rch p<<1|1
#define tl tre[p].l
#define tr tre[p].r
inline void push_down(int p){
if(!tre[p].cov) return;
int len=tr-tl+1;
tre[lch].bmx=-1;
tre[rch].bmx=-1;
tre[lch].sum=-1*(len-(len>>1));
tre[rch].sum=-1*(len>>1);
tre[lch].cov=tre[p].cov;
tre[rch].cov=tre[p].cov;
tre[p].cov=0;
return;
}
inline void build(int p,int l,int r){
tl=l,tr=r;
tre[p].sum=-(r-l+1);
tre[p].bmx=-1;
tre[p].cov=0;
if(l==r) return;
int mid=l+r>>1;
build(lch,l,mid);
build(rch,mid+1,r);
tre[p].merge(tre[lch],tre[rch]);
return;
}
inline void update(int p,int d,int w){
if(tl==tr){
tre[p].sum+=w;
tre[p].bmx+=w;
return;
}
push_down(p);
int mid=tl+tr>>1;
if(d<=mid) update(lch,d,w);
else update(rch,d,w);
tre[p].merge(tre[lch],tre[rch]);
}
inline void cover(int p,int l,int r){
if(l<=tl&&tr<=r){
tre[p].bmx=-1;
tre[p].sum=-(tr-tl+1);
tre[p].cov=1;
return;
}
push_down(p);
int mid=tl+tr>>1;
if(l<=mid) cover(lch,l,r);
if(r>mid) cover(rch,l,r);
tre[p].merge(tre[lch],tre[rch]);
return;
}
inline Tree query(int p,int l,int r){
if(l<=tl&&tr<=r) return tre[p];
push_down(p);
int mid=tr+tl>>1;
if(r<=mid) return query(lch,l,r);
if(l>mid) return query(rch,l,r);
Tree res;
res.merge(query(lch,l,r),query(rch,l,r));
return res;
}
#undef lch
#undef rch
#undef tl
#undef tr
inline void Inquire(int u){
ans.sum=0,ans.bmx=-1;
while(top[u]!=1){
ans.merge(query(1,dfn[top[u]],dfn[u]),ans);
u=faz[top[u]];
}
ans.merge(query(1,1,dfn[u]),ans);
return;
}
int main(){
n=in,q=in;
for(int v=2;v<=n;++v){
int u=in;
add(u,v);
}
DFS1(0,1);
DFS2(1,1);
build(1,1,n);
for(int i=1;i<=q;++i){
int opt=in,u=in;
if(opt==1){
update(1,dfn[u],1);
}else if(opt==2){
cover(1,dfn[u],dfn[u]+siz[u]-1);
//remove the influence of the upper dots
//which is because when we do operation 1,
//we only modify one dot instead of all related dots
//therefore when we cover a sub-tree
//we probably ignore the influence of upper dots
Inquire(u);
if(ans.bmx>=0) update(1,dfn[u],-ans.bmx-1);//ans.bmx(originally search result)-ans.bmx-1=-1
}else if(opt==3){
Inquire(u);
if(ans.bmx>=0) puts("black");
else puts("white");
}
}
return 0;
}
註釋的翻譯:
//去掉上面的點的影響
//這是因爲當我們做操作1時,
//我們只修改一個點而不是所有相關的點
//因此,當我們覆蓋一個子樹
//我們可能忽略了上面圓點的影響