LGP8844 [CZCup R4-P] 小卡与落叶 学习笔记
LGP8844 [CZCup R4-P] 小卡与落叶 学习笔记
题意简述
给定一棵 \(n\) 个结点的树,每个结点有黄色或绿色中的两种颜色之一。一开始整棵树都是绿的。
需要支持两种操作共 \(m\) 次:
1 x:将整棵树染绿,然后把所有深度 \(\ge x\) 的结点染黄。2 u:询问 \(u\) 的子树里有多少结点是黄的。
\(n,m\le 10^5\)。
做法解析
先把树dfs一遍,这样可以用 \(\text{dfn}\) 判断子树关系。
然后我们发现询问“黄”就是在问结点的深度是否大于 \(d\),其中 \(d\) 是当前结点为黄的最小深度。这个染色操作就是在改变当前的 \(d\)。
所以,实际上这就是个砂壁离线二维数点。不需要我教你怎么做吧。
代码实现
#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=1e5+5;
int N,M,Opt,X,Y;
vector<int> Tr[MaxN];
void addudge(int u,int v){
Tr[u].push_back(v);
Tr[v].push_back(u);
}
int dfn[MaxN],dcnt,siz[MaxN],dep[MaxN];
vector<int> P[MaxN];
void dfs(int u,int f){
dfn[u]=++dcnt,siz[u]=1,dep[u]=dep[f]+1;P[dep[u]].push_back(u);
for(int v : Tr[u])if(v!=f)dfs(v,u),siz[u]+=siz[v];
}
struct quer{int u,l,r,id;};
vector<quer> Q[MaxN];
struct BinidTree{
int n,t[MaxN];
void init(int x){n=x,fill(t,t+n+1,0);}
int lowbit(int x){return x&(-x);}
void add(int p,int x){for(;p<=n;p+=lowbit(p))t[p]+=x;}
int gts(int p){int res=0;for(;p;res+=t[p],p-=lowbit(p));return res;}
int getsum(int l,int r){return gts(r)-gts(l-1);}
}BiT;
int cdep,ans[MaxN];
int main(){
readis(N,M);BiT.init(N),cdep=N+1;
for(int i=1;i<N;i++)readis(X,Y),addudge(X,Y);
dfs(1,0);for(int i=1;i<=M;i++){
readis(Opt,X),ans[i]=-1;
if(Opt==1)cdep=X;
if(Opt==2)Q[cdep-1].push_back({X,dfn[X],dfn[X]+siz[X]-1,i});
}
for(int i=0;i<=N;i++){
for(auto u : P[i])BiT.add(dfn[u],1);
for(auto [u,l,r,id] : Q[i])ans[id]=siz[u]-BiT.getsum(l,r);
}
for(int i=1;i<=M;i++)if(ans[i]!=-1)writil(ans[i]);
return 0;
}
浙公网安备 33010602011771号