简要题意

给出一个 \(n\) 个节点的以 \(1\) 为根的树,每一个节点 \(i\) 带权 \(w_i\),初始时所有节点的权均为 \(0\)。有 \(m\) 个操作,支持以下操作:

  • 1 x,对于所有树上节点 \(i\),进行以下操作:
\[w_i=\begin{cases}1&(\operatorname{Depth}({i})\geq x)\\0&(\text{otherwise})\end{cases}
\]
  • 2 x,询问以 \(x\) 为根的子树的所有节点的权值和。

\(1 \leq n,m \leq 10^{5}\),允许离线

思路

首先可以得出 2 操作的答案仅与之前的最后一次 1 操作有关,所以我们把操作离线下来,设最后一次 \(1\) 操作是 1 t,那么操作 2 v 其实是在求以 \(t\) 为根的子树中有多少个深度大于等于 \(t\) 的节点。统计深度自然想到按照深度建一个权值线段树森林。树上 DFS 处理询问。先把儿子合并到父亲上,然后直接回答查询即可(这里询问是线段树基本操作,不讲)。

时间复杂度 \(O(m\log n)\)。

代码

#include <bits/stdc++.h>
#define int long long
#define ls(i) (t[i].ls)
#define rs(i) (t[i].rs)
#define mid ((l+r)>>1)
using namespace std; const int N = 1e5+5;
struct node{
int ls,rs,v;
} t[N<<8];
int root[100005],tot;
int n,m; inline void newnode(int &i){
if(!i)i=(++tot);
} void pushup(int i){
t[i].v=t[ls(i)].v+t[rs(i)].v;
} void insert(int p,int v,int &i,int l,int r){
newnode(i);
if(l==r){
t[i].v++;
return;
}
if(p<=mid){
insert(p,v,ls(i),l,mid);
}
else{
insert(p,v,rs(i),mid+1,r);
}
pushup(i);
} void merge(int &x,int &y){
if(x==0||y==0){
if(y)x=y;
if(x)y=x;
return;
}
t[x].v+=t[y].v;
merge(ls(x),ls(y));
merge(rs(x),rs(y));
} int query(int ql,int qr,int i,int l,int r){
if(!i)return 0;
if(ql<=l&&r<=qr){
return t[i].v;
}
int res=0;
if(ql<=mid){
res+=query(ql,qr,ls(i),l,mid);
}
if(qr>mid){
res+=query(ql,qr,rs(i),mid+1,r);
}
return res;
} struct edge{
int nxt,to;
} g[1000005];
int head[1000005],ec;
void add(int u,int v){
g[++ec].nxt=head[u];
g[ec].to=v;
head[u]=ec;
} int dep[1000005];
struct Query{
int x,tmd;
Query(int X=0,int TMD=0){
x=X,tmd=TMD;
}
}; int ret[1000005];
vector<Query> q[100005]; void dfs(int u,int fa){
dep[u]=dep[fa]+1;
for(int i=head[u];i;i=g[i].nxt){
int v=g[i].to;
if(v==fa)continue;
dfs(v,u);
}
} void solve(int u,int fa){
for(int i=head[u];i;i=g[i].nxt){
int v=g[i].to;
if(v==fa)continue;
solve(v,u);
merge(root[u],root[v]);
}
for(Query i:q[u]){
ret[i.tmd]=query(i.x,n,root[u],1,n);
}
} signed main(){
ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
cin>>n>>m;
for(int i=1,u,v;i<n;i++){
cin>>u>>v;
add(u,v);add(v,u);
}
dfs(1,0);
for(int i=1;i<=n;i++){
insert(dep[i],1,root[i],1,n);
}
int last_dep=n+1,two_cnt=0;
while(m--){
int op,u;
cin>>op>>u;
if(op==1){
last_dep=u;
continue;
}
q[u].push_back(Query(last_dep,(++two_cnt)));
}
solve(1,0);
for(int i=1;i<=two_cnt;i++){
cout<<ret[i]<<'\n';
}
return 0;
}

最新文章

  1. 设计模型MVC和JavaBean
  2. 嵌套div中margin-top转移问题的解决办法
  3. 学习mongo系列(六)limit(munber),skip(number)
  4. zepto源代码解读
  5. static_cast, dynamic_cast, const_cast
  6. 【转】 Java 多线程之一
  7. Windows 7系统安装MySQL5.5.21图解
  8. Java基础学习中一些词语和语句的使用
  9. Sublime Text2 按shift键选择不了的问题
  10. html弹窗,与弹出对话框
  11. python基础1 day2
  12. 2018ICPC青岛现场赛 重现训练
  13. 百度ueditor的图片上传,前后端交互使用
  14. BZOJ2212 [POI2011] Tree Rotations 【treap】
  15. 【Vue课堂】Vue.js 父子组件之间通信的十种方式
  16. 排查java进程cpu占用高的问题
  17. 5 个关键点!优化你的 UI 原型设计
  18. Redis勒索事件爆发,如何避免从删库到跑路?
  19. linux通过c++实现线程池类
  20. 检索数据(mysqli的面向对象用法)

热门文章

  1. C语言------结构体和共用体
  2. CSP-S游记
  3. Linux系统安装python
  4. 修改linux系统时间
  5. 【深入浅出 Yarn 架构与实现】4-1 ResourceManager 功能概述
  6. SerialException:Cannot configure port something went wrong
  7. Jmeter中用户定义的变量跟用户参数的区别
  8. SQL注入绕waf思路总结
  9. 【PPT】NET Conf China 2022,主题:C#在iNeuOS工业互联网操作系统的开发及应用
  10. 【PostgreSQL】pgsql编写函数实现批量删除数字结尾的备份表