国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

淺談主席樹

2019-11-08 18:38:16
字體:
來源:轉載
供稿:網友

淺談主席樹思想以及模板


淺談主席樹思想以及模板主席樹的原理主席樹的思想主席樹的應用主席樹的模板主席樹的題目

首先,作為一名蒟蒻,很早就聽說過主席樹這個高大上的名字,然而一直都不會(其實只是沒敲過代碼)。所以,今天就來正式的談一談主席樹,本蒻著此文以記之

主席樹的原理

它的原理十分簡單,就是想辦法把前后兩棵線段樹進行持久化并盡可能合并以節約空間。最后的空間復雜度大概是O(nlogn) 這里寫圖片描述

然而這個時候它就會很自然地要求我們保證所有線段樹的結構均完全相同,這時我們可以通過建立一個參考序列,里面保存著區間,映射到主席樹里就是保存和這一區間有關的信息,然后對這個參考區間進行二分,這樣映射到每棵線段樹中它們的結構都將會是完全相同的

主席樹的思想

就我個人的理解,主席樹的本質,其實就是一顆可持久化線段樹。但是本來一顆好好的線段樹,我們為什么要把他們造成可持久化的呢,這是因為我們想訪問多個區間或多個子線段樹。此處的意思是我們建立一顆普通的線段樹時,我們只是使這棵線段樹對應了一個區間[1...n],但往往我們并不想僅僅去訪問這一棵線段樹上的信息或者說這一段區間上的信(這可能是由于一棵線段樹上的信息量太少而不能滿足我們的需要)。有時我們可以直接使用原有的那棵線段樹上的信息(比如我們想查詢一段子區間的Maximum/Minimum或者是Sum什么的),然而有的時候就并不可以(如我們想求一段子區間中的第K大值)。對于什么時候Single-Segment-Tree會出現問題應該根據具體情況就可以判斷出來

主席樹的應用

作為一名蒟蒻,我做的題非常少,對于這種神奇的數據結構,應用可能有求某段區間中第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]; 主席樹的題目

這就等著其他的博文來進行補充啦O(∩_∩)O~


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 惠州市| 成都市| 临泽县| 达孜县| 平阴县| 台州市| 安新县| 碌曲县| 石棉县| 凯里市| 伊宁市| 毕节市| 龙山县| 礼泉县| 藁城市| 定兴县| 天柱县| 临漳县| 改则县| 法库县| 民和| 通河县| 兴和县| 龙门县| 古浪县| 龙南县| 霍城县| 榆林市| 西盟| 浦东新区| 和平区| 甘孜县| 荣成市| 和硕县| 霞浦县| 雅江县| 左贡县| 徐闻县| 峨眉山市| 阳城县| 保定市|