ABC202E Count Descendants
线段树合并模板题。
每次询问就是给定有序数对
考虑对每一个点开一个长度为
每递归到叶节点
回溯时,将
显然,时间复杂度的瓶颈在于合并操作,考虑如何优化这一步。
考虑线段树合并,对每一个
注意不能将
由于每次会多开
树上启发式合并 也可以解决本题,时间复杂度仍然是
下面是线段树合并的代码:
const int N=2e5+8;
int n,m;
struct Graph{
int head[N],edge_tot=1,to[N],next[N];
void add_edge(int u,int v){
edge_tot++;
to[edge_tot]=v;
next[edge_tot]=head[u];
head[u]=edge_tot;
}
}Tree;
int depth[N];
int rt[N];
struct Segemnt_Tree{
int ocnt,ls[N<<6],rs[N<<6],sum[N<<6];
void push_up(int o){
sum[o]=sum[ls[o]]+sum[rs[o]];
}
void insert(int &o,int l,int r,int pos){
o=++ocnt;
if(l==r){
sum[o]++;
return;
}
int mid=(l+r)/2;
if(pos<=mid)
insert(ls[o],l,mid,pos);
else
insert(rs[o],mid+1,r,pos);
push_up(o);
}
int query(int o,int l,int r,int pos){
if(o==0)
return 0;
if(l==r)
return sum[o];
int mid=(l+r)/2;
if(pos<=mid)
return query(ls[o],l,mid,pos);
else
return query(rs[o],mid+1,r,pos);
}
int merge(int u,int v){
if(u==0||v==0)
return u+v;
int o=++ocnt;
ls[o]=merge(ls[u],ls[v]);
rs[o]=merge(rs[u],rs[v]);
sum[o]=sum[u]+sum[v];
return o;
}
}smt;
void dfs(int u,int father){
depth[u]=depth[father]+1;
smt.insert(rt[u],1,n,depth[u]);
for(int i=Tree.head[u];i;i=Tree.next[i]){
int v=Tree.to[i];
dfs(v,u);
rt[u]=smt.merge(rt[u],rt[v]);
}
}
bool Mend;
int main(){
// File_Work();
fprintf(stderr,"%.3lf MB\n\n\n",(&Mbegin-&Mend)/1048576.0);
n=read();
for(int i=2;i<=n;i++){
int father=read();
Tree.add_edge(father,i);
}
dfs(1,0);
m=read();
while(m--){
int a=read(),b=read()+1;
write(smt.query(rt[a],1,n,b)),putchar('\n');
}
fprintf(stderr,"\n\n\n%.0lf ms",1e3*clock()/CLOCKS_PER_SEC);
return 0;
}
线段树合并的题,通常可以先想
思想几乎一样的题:CF208E Blood Cousins。
另一道线段树合并模板题:CF600E Lomsat gelral。
分类:
OI / 题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现