LGP8844 [CZCup R4-P] 小卡与落叶 学习笔记

LGP8844 [CZCup R4-P] 小卡与落叶 学习笔记

Luogu Link

题意简述

给定一棵 \(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;
}
posted @ 2025-05-14 16:49  矞龙OrinLoong  阅读(13)  评论(0)    收藏  举报