CF1975E Chain Queries 题解
题目简述
给一棵节点为黑色或白色的树。每次修改一个结点的颜色并询问黑色节点是否构成一条链。
题目思路
我们将一个节点的度数定义为和它相邻的黑点数。
不难发现,黑色节点构成一条链当且仅当她们的度数只是 \(1\) 或 \(2\),且度数为一的只有两个(链的两端节点度数为 \(1\),其余节点是 \(2\)),并且每次修改时只会修改她的父亲和儿子,所以我们把树按 BFS 序拍到序列上(这样一个结点的儿子就是连续的了),用线段树维护其度数最大值,最小值,最小值个数即可。对于节点是否为白色我们额外维护一个标记,这个也不难处理。时间复杂度 \(O(n\log n)\)。
记得特判 \(0,1,2\) 个黑点的情况。
场上调了一个小时,赛后看到线性做法的我是小丑
代码
#include<bits/stdc++.h>
using namespace std;
inline void rd(){}
template<typename T,typename ...U>
inline void rd(T &x,U &...args){
char ch=getchar();
T f=1;x=0;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
x*=f;rd(args...);
}
const int N=2e5+5;
int T,n,Q;
int a[N],fst[N],nxt[N<<1],v[N<<1],idx;
inline void Add(int a,int b){
v[idx]=b,nxt[idx]=fst[a];
fst[a]=idx++;
}
int fa[N],degb[N],sons[N],son[N];
void DFS(int x,int f){
fa[x]=f;
for(int i=fst[x];~i;i=nxt[i]){
int y=v[i];
if(y==f)continue;
sons[x]++;
DFS(y,x);
}
}
queue<int> q;
int dfn[N],fdfn[N],cnt;
void BFS(int s){
q.push(s);
while(!q.empty()){
int x=q.front();
q.pop();
dfn[++cnt]=x;
fdfn[x]=cnt;
for(int i=fst[x];~i;i=nxt[i]){
int y=v[i];
if(y==fa[x])continue;
if(!son[x])son[x]=y;
q.push(y);
}
}
}
struct Segment{
int mn,mnnum,mx,ifw,tag;
}t[N<<2];
inline void Push_up(int i){
if(t[i*2].ifw&&t[i*2+1].ifw)return t[i].ifw=1,t[i].tag=0,void();
t[i].ifw=0;
if(t[i*2].ifw)t[i]=t[i*2+1];
else if(t[i*2+1].ifw)t[i]=t[i*2];
else{
t[i].mn=min(t[i*2].mn,t[i*2+1].mn);
if(t[i*2].mn<t[i*2+1].mn)t[i].mnnum=t[i*2].mnnum;
else if(t[i*2].mn>t[i*2+1].mn)t[i].mnnum=t[i*2+1].mnnum;
else t[i].mnnum=t[i*2].mnnum+t[i*2+1].mnnum;
t[i].mx=max(t[i*2].mx,t[i*2+1].mx);
}
t[i].tag=0;
/*
这里一定要清空标记,因为叶子结点的标记按我的写法是会留在上面的,
平常没什么问题,但是这里因为有直接继承可能会把儿子的标记吸上来,
这样就完美的寄了。
*/
}
inline void Addtag(int i,int x){
t[i].mn+=x,t[i].mx+=x;
t[i].tag+=x;
}
inline void Push_down(int i){
if(t[i].tag){
Addtag(i*2,t[i].tag);
Addtag(i*2+1,t[i].tag);
t[i].tag=0;
}
}
void Build(int i,int l,int r){
t[i].tag=0;
if(l==r){
t[i].ifw=!(a[dfn[l]]);
t[i].mn=t[i].mx=degb[dfn[l]];
t[i].mnnum=1;
return ;
}
int mid=(l+r)>>1;
Build(i*2,l,mid);
Build(i*2+1,mid+1,r);
Push_up(i);
}
void Update(int i,int l,int r,int L,int R,int x){
if(L<=l&&r<=R){
Addtag(i,x);
return ;
}
int mid=(l+r)>>1;
Push_down(i);
if(L<=mid)Update(i*2,l,mid,L,R,x);
if(R>mid)Update(i*2+1,mid+1,r,L,R,x);
Push_up(i);
}
void Update_col(int i,int l,int r,int x,int col){
if(l==r)return t[i].ifw=(!col),void();
int mid=(l+r)>>1;
Push_down(i);
if(x<=mid)Update_col(i*2,l,mid,x,col);
else Update_col(i*2+1,mid+1,r,x,col);
Push_up(i);
}
int blacks=0;
signed main(){
rd(T);
while(T--){
rd(n,Q);
idx=cnt=blacks=0;
for(int i=1;i<=n;i++)fst[i]=-1,degb[i]=sons[i]=son[i]=0;
for(int i=1;i<=n;i++)rd(a[i]),blacks+=a[i];
for(int i=1;i<n;i++){
int x,y;rd(x,y);
Add(x,y);Add(y,x);
if(a[x])degb[y]++;
if(a[y])degb[x]++;
}
DFS(1,1);
BFS(1);
Build(1,1,n);
while(Q--){
int u;rd(u);
a[u]=!a[u];
if(a[u]){
blacks++;
if(son[u])Update(1,1,n,fdfn[son[u]],fdfn[son[u]]+sons[u]-1,1);
if(u!=1)Update(1,1,n,fdfn[fa[u]],fdfn[fa[u]],1);
Update_col(1,1,n,fdfn[u],1);
}else{
blacks--;
if(son[u])Update(1,1,n,fdfn[son[u]],fdfn[son[u]]+sons[u]-1,-1);
if(u!=1)Update(1,1,n,fdfn[fa[u]],fdfn[fa[u]],-1);
Update_col(1,1,n,fdfn[u],0);
}
if(t[1].ifw)printf("No\n");
else if(blacks==1)printf("Yes\n");
else if(t[1].mn==1&&t[1].mx<=2&&t[1].mnnum==2){
printf("Yes\n");
}else printf("No\n");
}
}
return 0;
}
本文作者:KIreteria
本文链接:https://www.cnblogs.com/11-twentythree/p/18229830
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步