动态开点线段树(多棵线段树)的内存分配与回收
来源:互联网 发布:高性价比耳麦知乎 编辑:程序博客网 时间:2024/05/29 07:05
前言
线段树,是一个很好用的能支持O(logn)区间操作的数据结构,随着做一些稍微烦一点的题,有时候会发现有些情况要开一个数组的线段树,更有甚者要树套树,而在很多情况下线段树就不能把所有点都开满了(否则会MLE内存超限),于是就出现了线段树的动态开点写法
基本思想
与普通的线段树相同,动态开点线段树只是一开始每一个节点都没有,insert的时候,如果遇到节点是空的,那么就声明这个点,询问的时候只访问询问的区间中非空节点,这样一来,时间复杂度没有问题还是O(
但是这么做当遇到树套树的时候,空间复杂度就会炸的很惨,为O(有过值的节点的数量*
那怎么优化呢,delete的时候如果遇到这个节点的儿子都是空的,那么就删掉这个点,回收这个点的内存,这样空间复杂度就能优化到O(有值节点数量最多时的节点数*
例题
SDOI2014旅行
https://www.luogu.org/problemnew/show/3313
题目大意
现在有n个节点的树,每个节点上有个颜色并且有个权值,要求支持:
1.询问树上的一条路径上某颜色的权值和
2.询问树上的一条路径上某颜色的最大权值
3.修改某节点的权值
4.修改某节点的颜色
这一题只要树链剖分,每个颜色都开一棵线段树,支持区间求和和区间max,当然不能开完所以点,只要动态开点就好了
动态开点的打好,可以练一练回收内存的方法,我的方法是开一个vector储存没有用过的内存节点
这个是我的AC代码,我用的是指针
#include<cstdio>#include<cstring>#include<cctype>namespace fast_IO{ const int IN_LEN=10000000,OUT_LEN=10000000; char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf; char *lastin=ibuf+IN_LEN; const char *lastout=ibuf+OUT_LEN-1; inline char getchar_() { if(ih==lastin)lastin=ibuf+fread(ibuf,1,IN_LEN,stdin),ih=ibuf; return (*ih++); } inline void putchar_(const char x) { if(ih==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf; *oh++=x; } inline void flush(){fwrite(obuf, 1, oh - obuf, stdout);}}using namespace fast_IO;//#define getchar() getchar_()//#define putchar(x) putchar_((x))typedef long long LL;#define rg registertemplate <typename T> inline T max(const T a,const T b){return a>b?a:b;}template <typename T> inline T min(const T a,const T b){return a<b?a:b;}template <typename T> inline T abs(const T a){return a>0?a:-a;}template <typename T> inline void swap(T&a,T&b){T c=a;a=b;b=c;}template <typename T> inline T gcd(const T a,const T b){if(a%b==0)return b;return gcd(b,a%b);}template <typename T> inline void read(T&x){ char cu=getchar();x=0;bool fla=0; while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();} while(isdigit(cu))x=x*10+cu-'0',cu=getchar(); if(fla)x=-x; }template <typename T> void printe(const T x){ if(x>=10)printe(x/10); putchar(x%10+'0');}template <typename T> inline void print(const T x){ if(x<0)putchar('-'),printe(-x); else printe(x);}const int MAX=524288,MAXN=100007,MAXM=200007;int n,m,q;int head[MAXN],nxt[MAXM],tow[MAXM],tmp=1;inline void addb(const int a,const int b){ tmp++; nxt[tmp]=head[a]; head[a]=tmp; tow[tmp]=b;}int v[MAXN],fr[MAXN],fa[MAXN],size[MAXN],dep[MAXN],tim=0,son[MAXN],top[MAXN],tid[MAXN],bak[MAXN];void dfs1(const int u,int las,int depth){ fa[u]=las; dep[u]=depth; size[u]=1; for(rg int i=head[u];~i;i=nxt[i]) { const int v=tow[i]; if(v!=las) { dfs1(v,u,depth+1); size[u]+=size[v]; if(son[u]==-1||size[son[u]]<size[v]) son[u]=v; } }}void dfs2(const int u,const int tp){ top[u]=tp; tid[u]=++tim; bak[tim]=u; if(son[u]==-1)return; dfs2(son[u],tp); for(rg int i=head[u];~i;i=nxt[i]) { int v=tow[i]; if(v!=fa[u]&&v!=son[u]) dfs2(v,v); } }int l[MAX],r[MAX],mid[MAX];struct node{ node *lson,*rson; int irt,maxx;}Q[2000001],*root[100001];#include<vector>std::vector<node*>bin;inline node *new_node(){ node *res=bin[bin.size()-1]; bin.pop_back(); res->lson=res->rson=0; res->irt=res->maxx=0; return res;}inline void del_node(node *res){ bin.push_back(res);}void ini(const int root,const int ll,const int rr){ l[root]=ll,mid[root]=(ll+rr)>>1,r[root]=rr; if(ll==rr)return; ini(root<<1,ll,mid[root]),ini(root<<1|1,mid[root]+1,rr);}inline void update(node *ROOT){ ROOT->irt=ROOT->maxx=0; if(ROOT->lson)ROOT->irt+=ROOT->lson->irt,ROOT->maxx=max(ROOT->maxx,ROOT->lson->maxx); if(ROOT->rson)ROOT->irt+=ROOT->rson->irt,ROOT->maxx=max(ROOT->maxx,ROOT->rson->maxx); }void insert(node *ROOT,const int root,const int wan,const int ins){ if(l[root]==r[root]){ROOT->irt=ins,ROOT->maxx=ins;return;} if(wan<=mid[root]) { if(!ROOT->lson)ROOT->lson=new_node(); insert(ROOT->lson,root<<1,wan,ins); } else { if(!ROOT->rson)ROOT->rson=new_node(); insert(ROOT->rson,root<<1|1,wan,ins); } update(ROOT);}node *del(node *ROOT,const int root,const int wan){ if(l[root]==r[root]) { del_node(ROOT); return 0; } if(wan<=mid[root]) { ROOT->lson=del(ROOT->lson,root<<1,wan); if(ROOT->lson==0&&ROOT->rson==0) { del_node(ROOT); return 0; } } else { ROOT->rson=del(ROOT->rson,root<<1|1,wan); if(ROOT->lson==0&&ROOT->rson==0) { del_node(ROOT); return 0; } } update(ROOT); return ROOT;}int search_irt(node *ROOT,const int root,const int ll,const int rr){ if(l[root]==ll&&r[root]==rr)return ROOT->irt; if(mid[root]>=rr) { if(ROOT->lson)return search_irt(ROOT->lson,root<<1,ll,rr); return 0; } else if(mid[root]<ll) { if(ROOT->rson)return search_irt(ROOT->rson,root<<1|1,ll,rr); return 0; } else { int res=0; if(ROOT->lson)res+=search_irt(ROOT->lson,root<<1,ll,mid[root]); if(ROOT->rson)res+=search_irt(ROOT->rson,root<<1|1,mid[root]+1,rr); return res; }}int search_maxx(node *ROOT,const int root,const int ll,const int rr){ if(l[root]==ll&&r[root]==rr)return ROOT->maxx; if(mid[root]>=rr) { if(ROOT->lson)return search_maxx(ROOT->lson,root<<1,ll,rr); return 0; } else if(mid[root]<ll) { if(ROOT->rson)return search_maxx(ROOT->rson,root<<1|1,ll,rr); return 0; } else { int res=0; if(ROOT->lson)res=max(res,search_maxx(ROOT->lson,root<<1,ll,mid[root])); if(ROOT->rson)res=max(res,search_maxx(ROOT->rson,root<<1|1,mid[root]+1,rr)); return res; }}inline int ssearch_irt(node *ROOT,int a,int b){ int s=0; while(top[a]!=top[b]) { if(dep[top[a]]<dep[top[b]])swap(a,b); s=s+search_irt(ROOT,1,tid[top[a]],tid[a]); a=fa[top[a]]; } if(dep[a]>dep[b])swap(a,b); s=s+search_irt(ROOT,1,tid[a],tid[b]); return s;}inline int ssearch_maxx(node *ROOT,int a,int b){ int s=0; while(top[a]!=top[b]) { if(dep[top[a]]<dep[top[b]])swap(a,b); s=max(s,search_maxx(ROOT,1,tid[top[a]],tid[a])); a=fa[top[a]]; } if(dep[a]>dep[b])swap(a,b); s=max(s,search_maxx(ROOT,1,tid[a],tid[b])); return s;}inline char get_char(){ char cu=getchar(); while(cu<'A'&&cu>'Z')cu=getchar(); return cu;}inline int getopt(){ char a=get_char(),b=get_char(); if(a=='C') { if(b=='C')return 1; return 2; } else { if(b=='S')return 3; return 4; }}int main(){ memset(head,-1,sizeof(head)); memset(son,-1,sizeof(son)); read(n),read(q); ini(1,1,n); for(rg int i=0;i<=2000000;i++)bin.push_back(&Q[i]); for(rg int i=1;i<=100000;i++)root[i]=new_node(); for(rg int i=1;i<=n;i++)read(v[i]),read(fr[i]); for(rg int i=1;i<n;i++) { int a,b;read(a),read(b); addb(a,b),addb(b,a); } dfs1(1,0,1),dfs2(1,1); for(rg int i=1;i<=n;i++) insert(root[fr[i]],1,tid[i],v[i]); for(rg int i=1;i<=q;i++) { int opt=getopt(),ll,rr;read(ll),read(rr); if(opt==1) { del(root[fr[ll]],1,tid[ll]); if(root[fr[ll]]==0)root[fr[ll]]=new_node(); fr[ll]=rr; insert(root[fr[ll]],1,tid[ll],v[ll]); } else if(opt==2) { v[ll]=rr; insert(root[fr[ll]],1,tid[ll],v[ll]); } else if(opt==3)print(ssearch_irt(root[fr[ll]],ll,rr)),putchar('\n'); else print(ssearch_maxx(root[fr[ll]],ll,rr)),putchar('\n'); } return flush(),0;}
结语
动态开点线段树其实是一个很好用的技巧,就算加一个分配、回收内存的东西也不难,具体一定要用分配回收内存的题呢,我做到过,具体在这里我就不介绍了
- 动态开点线段树(多棵线段树)的内存分配与回收
- NOIP2017d2t3 列队 动态开点线段树
- bzoj3531(树链剖分+动态开点线段树)
- 动态开点线段树(Radio stations,762E)
- [BZOJ4372][动态树分治(点分树)][动态开点线段树]烁烁的游戏
- BZOJ-3531 旅行 树链剖分+动态开点线段树
- Bzoj3531:[Sdoi2014]旅行:树链剖分+动态开点线段树
- poj2528(动态开点线段树——过不了)
- [BZOJ3531] SDOI2014 树链剖分+动态开点线段树
- |BZOJ 3531|树链剖分|动态开点线段树|[Sdoi2014]旅行
- bzoj3531 [Sdoi2014]旅行(树链剖分+动态开点线段树)
- bzoj4999 This Problem Is Too Simple!(树链剖分+动态开点线段树)
- 【BZOJ3531】旅行,树链剖分+开点线段树
- BZOJ 3531: [Sdoi2014]旅行【树剖+动态开点线段树【听说有人写平衡树?【滑稽
- bzoj 4999 This problem is too simple 树链剖分+动态开点线段树
- JAVA 内存的分配与回收
- 内存的连续分配与回收算法
- JVM的垃圾回收与内存分配
- Spring MVC数据绑定-01
- ios取消uitableviewcell点击效果
- css画图笔记
- jQuery Mobile 过渡效果
- 用Maven创建第一个web项目
- 动态开点线段树(多棵线段树)的内存分配与回收
- 微信JS-SDK实现自定义分享功能,分享给朋友,分享到朋友圈
- Python海量数据处理之_Hadoop(二)概念和原理
- VUE 生命周期
- 关于resnet
- git相关命令-下
- MSMQ 的理解
- [Err] 1055
- 对采样与量化之中科院刘定生老师留的思考题