线段树合并的复杂度
线段树合并的时间复杂度是
int mer(int x,int y){
if(!x||!y)return x^y; t[x]+=t[y];
return L[x]=mer(L[x],L[y]),R[x]=mer(R[x],R[y]),x;
}
因为每个点只会在自己被删除(情况 1)或父亲被删除且自己未删除的(即合并时另一个子树为空,情况 2)情况下被枚举。(被删除指的是在以后的线段树合并中不会被枚举到)。
情况 1 显然是
所以在树上用线段树合并是有时间复杂度保障的,大胆使用即可(常树较大)。
当题目的内存为
或 时建议加上垃圾回收,避免因为卡内存造成的 惨案。
P3605 [USACO17JAN] Promotion Counting P:
随便找的一个简单题,直接线段树合并、区间询问即可。
// qwq
#include <bits/stdc++.h>
using namespace std;
constexpr int N=1e5+12;
int L[N*100],R[N*100],cnt,t[N*100];
int a[N],rt[N],ans[N],n;
vector<int>e[N];
void ins(int& k,int l,int r,int x){
if(!k)k=++cnt;t[k]++;
if(l==r)return;int mid=l+r>>1;
if(x<=mid)ins(L[k],l,mid,x);
else ins(R[k],mid+1,r,x);
}
int ask(int k,int l,int r,int x,int y){
if(x>y||l>r||l>y||x>r)return 0;
if(l>=x&&r<=y)return t[k];int mid=l+r>>1;
return ask(L[k],l,mid,x,y)+ask(R[k],mid+1,r,x,y);
}
int mer(int x,int y){
if(!x||!y)return x^y; t[x]+=t[y];
return L[x]=mer(L[x],L[y]),R[x]=mer(R[x],R[y]),x;
}
void dfs(int u){
ins(rt[u],1,1e9,a[u]);
for(int v:e[u])dfs(v),rt[u]=mer(rt[u],rt[v]);
ans[u]=ask(rt[u],1,1e9,a[u]+1,1e9);
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=2,x;i<=n;i++)cin>>x,e[x].push_back(i);
dfs(1);
for(int i=1;i<=n;i++)cout<<ans[i]<<'\n';
return 0;
}
本文作者:fzrcy
本文链接:https://www.cnblogs.com/fzrcy/p/17713382.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步