浅谈主席树思想以及模板主席树的原理主席树的思想主席树的应用主席树的模板主席树的题目
首先,作为一名蒟蒻,很早就听说过主席树这个高大上的名字,然而一直都不会(其实只是没敲过代码)。所以,今天就来正式的谈一谈主席树,本蒻著此文以记之
它的原理十分简单,就是想办法把前后两棵线段树进行持久化并尽可能合并以节约空间。最后的空间复杂度大概是
然而这个时候它就会很自然地要求我们保证所有线段树的结构均完全相同,这时我们可以通过建立一个参考序列,里面保存着区间,映射到主席树里就是保存和这一区间有关的信息,然后对这个参考区间进行二分,这样映射到每棵线段树中它们的结构都将会是完全相同的
就我个人的理解,主席树的本质,其实就是一颗可持久化线段树。但是本来一颗好好的线段树,我们为什么要把他们造成可持久化的呢,这是因为我们想访问多个区间或多个子线段树。此处的意思是我们建立一颗普通的线段树时,我们只是使这棵线段树对应了一个区间[
作为一名蒟蒻,我做的题非常少,对于这种神奇的数据结构,应用可能有求某段区间中第K大值或者是求某段区间中某个或某段数字的出现次数等等,此处留坑待补
下面的这个模板的功能是求某段区间第K小的值(当然是用主席树实现的),代码巨丑,不喜勿喷
#include<cstdlib>#include<cstdio>#include<algorithm>#define maxn 100005#define Pii pair<int,int>#define Author Goseqhusing namespace std;typedef struct node{ int sum; node* left; node* right; node(int sum){ this->sum=sum; right=left=NULL; } node():sum(0),left(NULL),right(NULL){}}node;//主席树的结点node* list[maxn];node* op;node* op2;Pii line[maxn];Pii sline[maxn];//排序之后的line数组(参考区间)int n,m,a,b,c;void insert(int l,int r,int o,int i){ if(l==r) return; int m=(r-l)/2+l; if(line[i]>sline[m]){ op->left=op2->left; node* k=new node(op2->right->sum+1); op->right=k,op=k,op2=op2->right; insert(m+1,r,o*2+1,i); } else{ op->right=op2->right; node* k=new node(op2->left->sum+1); op->left=k,op=k,op2=op2->left; insert(l,m,o*2,i); } return;}//主席树的二分插值过程/*void init2(int l,int r,int x,node* now){ if(l==r) return; int m=(r-l)/2+l; if(x>sline[m]){ node* now->left=new node(0); node* now->right=new node(1); } else{ node* now->left=new node(1); node* now->right=new node(0); } init2(l,m,x,now->left); init2(m+1,r,x,now->right); return;}*///此处对应了另一种实现,即以第一棵有意义的线段树作为开头void init2(int l,int r,node* now){ if(l==r)return; int m=(r-l)/2+l; now->left=new node(); now->right=new node(); init2(l,m,now->left); init2(m+1,r,now->right); return;}//这里是用一棵虚拟的线段树作为开头,感觉更加简洁不易出错void init(){ //init2(1,n,line[1],list[1]); list[0]=new node(); init2(1,n,list[0]); for(int i=1;i<=n;i++){ op=list[i]=new node(),op2=list[i-1]; insert(1,n,1,i); } return;}int query(int l,int r){ if(l==r) return sline[l].first; int con=op2->left->sum-op->left->sum; int m=(r-l)/2+l; if(c>con){ c-=con; op=op->right,op2=op2->right; return query(m+1,r); } else{ op=op->left,op2=op2->left; return query(l,m); }}//询问过程int main(){ /*freopen("input.txt","r",stdin); freopen("output.txt","w",stdout);*/ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&line[i].first); line[i].second=i; sline[i]=line[i]; } sort(sline+1,sline+n+1); init(); for(int i=0;i<m;i++){ scanf("%d%d%d",&a,&b,&c); op=list[a-1],op2=list[b]; PRintf("%d/n",query(1,n)); } return 0;}这就等着其他的博文来进行补充啦O(∩_∩)O~
新闻热点
疑难解答