日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

线段树总结(一)【数据结构】

發(fā)布時間:2025/3/21 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 线段树总结(一)【数据结构】 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

最近學(xué)線段樹,先來總結(jié)一下知道的基礎(chǔ)知識。感覺這東西很靈活。

  自己現(xiàn)在的理解就是線段樹是來維護一個序列的區(qū)間查找與修改操作的數(shù)據(jù)結(jié)構(gòu),我覺得學(xué)好它可能更容易理解樹狀數(shù)組。就像有的網(wǎng)站上說,為什么需要線段樹,就是因為它綜合起來查找和修改的操作復(fù)雜度比較低,都是log級別的。基本線段樹都包括Build(),Update(),Query(),PushUp()函數(shù)。A[]數(shù)組存維護的原序列,sum[]數(shù)組存區(qū)間和。sum[]數(shù)組的下標其實是這棵樹從根節(jié)點到葉子節(jié)點的編號,每個編號對應(yīng)一個區(qū)間和,自然sum[1]對應(yīng)所維護的整個區(qū)間。由于sum[]數(shù)組不僅存每個點的值,還存區(qū)間的值,所以數(shù)組要開相當于A[]數(shù)組的4倍。

單點更新類:

HDU 1166??線段樹功能:update:單點增減 query:區(qū)間求和

這是到入門題。說的也很直白,就是區(qū)間的查詢和修改。用宏定義lson,rson方便一些。

1 #include<cstdio> 2 #define lson l,m,rt<<1 3 #define rson m+1,r,rt<<1|1 4 using namespace std; 5 const int maxn=50005; 6 int A[maxn],sum[maxn<<2]; 7 8 void PushUp(int rt) 9 { 10 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 11 } 12 13 void Build(int l,int r,int rt)//遞歸建樹 14 { 15 if(l==r){ 16 sum[rt]=A[l];//遞歸到葉子節(jié)點時,把初始值給對應(yīng)的sum[]數(shù)組的值。 17 return; 18 } 19 int m=(l+r)>>1; 20 Build(lson); 21 Build(rson); 22 PushUp(rt);//向上更新父節(jié)點的值,剛開始建樹時只有存葉子結(jié)點值的sum[]有值。 23 } 24 25 void Update(int pos,int val,int l,int r,int rt)//遞歸更新 26 { 27 if(l==r){ 28 sum[rt]+=val; 29 return; 30 } 31 int m=(l+r)>>1; 32 if(pos<=m) Update(pos,val,lson); 33 else Update(pos,val,rson); 34 PushUp(rt);//也是要向上返回更新父節(jié)點 35 } 36 37 int Query(int L,int R,int l,int r,int rt) 38 { 39 if(L<=l&&r<=R){//屬于[L,R]直接返回 40 return sum[rt]; 41 } 42 int m=(l+r)>>1; 43 int res=0; 44 if(L<=m) res+=Query(L,R,lson);//有交叉就遞歸 45 if(R>m) res+=Query(L,R,rson); 46 return res; 47 } 48 49 int main() 50 { 51 int T; 52 scanf("%d",&T); 53 for (int cas=1;cas<=T;cas++) 54 { 55 int N; 56 scanf("%d",&N); 57 for (int i=1;i<=N;i++) scanf("%d",&A[i]); 58 Build(1,N,1); 59 printf("Case %d:\n",cas); 60 char op[10]; 61 while(scanf("%s",op)) 62 { 63 int a,b; 64 if(op[0]=='E') break; 65 scanf("%d%d",&a,&b); 66 if(op[0]=='Q') 67 printf("%d\n",Query(a,b,1,N,1)); 68 else if(op[0]=='A') 69 Update(a,b,1,N,1); 70 else 71 Update(a,-b,1,N,1); 72 } 73 } 74 return 0; 75 } hdu 1166

HDU 1754?線段樹功能:update:單點替換 query:區(qū)間最值

這道題就是在把sum[]數(shù)組的存區(qū)間和作用變?yōu)榇鎱^(qū)間的最大值。所以就把sum[]變成MAX[]了。其實道理是一樣的。

1 #include<cstdio> 2 #include<algorithm> 3 #define lson l,m,rt<<1 4 #define rson m+1,r,rt<<1|1 5 using namespace std; 6 const int maxn=200005; 7 int MAX[maxn<<2],A[maxn]; 8 int N,M; 9 10 void PushUp(int rt) 11 { 12 MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]); 13 } 14 15 void Build(int l,int r,int rt) 16 { 17 if(l==r){ 18 MAX[rt]=A[l]; 19 return; 20 } 21 int m=(l+r)>>1; 22 Build(lson); 23 Build(rson); 24 PushUp(rt); 25 } 26 27 void Update(int pos,int val,int l,int r,int rt) 28 { 29 if(l==r){ 30 MAX[rt]=val; 31 return; 32 } 33 int m=(l+r)>>1; 34 if(pos<=m) Update(pos,val,lson); 35 else Update(pos,val,rson); 36 PushUp(rt); 37 } 38 39 int Query(int L,int R,int l,int r,int rt) 40 { 41 if(L<=l&&r<=R){ 42 return MAX[rt]; 43 } 44 int m=(l+r)>>1; 45 int res=0; 46 if(L<=m) res=max(res,Query(L,R,lson)); 47 if(R>m) res=max(res,Query(L,R,rson)); 48 return res; 49 } 50 51 int main() 52 { 53 while(scanf("%d%d",&N,&M)==2) 54 { 55 for (int i=1;i<=N;i++) scanf("%d",&A[i]); 56 Build(1,N,1); 57 int a,b; 58 char op; 59 for (int i=0;i<M;i++){ 60 scanf(" %c",&op); 61 scanf("%d%d",&a,&b); 62 if(op=='Q'){ 63 int ans=Query(a,b,1,N,1); 64 printf("%d\n",ans); 65 }else 66 { 67 Update(a,b,1,N,1); 68 } 69 } 70 } 71 return 0; 72 } hdu 1754

HDU 1394?線段樹功能:update:單點增減 query:區(qū)間求和

這道題求最小逆序數(shù)。線段樹怎么求逆序數(shù)呢?就是依次讀入序列時,把讀入的值加入線段樹,每次查詢時,就看比這個值大的區(qū)間有多少個元素,就是這個數(shù)對應(yīng)逆序數(shù)的個數(shù)了。而這道題不僅讓求逆序數(shù),而且序列還可以一位一位向后移,要求最少的逆序數(shù)。既然剛開始讀入序列已經(jīng)知道了一個逆序數(shù)個數(shù),那么后面考慮的就是向后移動一個數(shù)字會對當前結(jié)果造成什么影響。比如說序列是:1 3 6 9 0 8 5 7 4 2 當我把1放在最后面時,只需考慮有關(guān)1的逆序數(shù)增減。可以發(fā)現(xiàn),對于題目要求的n個數(shù)的序列,每次往后移動一個數(shù)a[i],也就是a[i]放在了最后(這里理解好就懂了,我想了挺長時間),增加的逆序數(shù)個數(shù)為n-a[i]-1(就是比a[i]大的數(shù)的個數(shù)),減少的逆序數(shù)個數(shù)為a[i](自然就是不大于a[i]的數(shù))。所以每移動一次,逆序數(shù)就變?yōu)?strong>cnt+=n-a[i]-1-a[i].?

1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #define lson l,m,rt<<1 5 #define rson m+1,r,rt<<1|1 6 using namespace std; 7 const int maxn=5005; 8 int a[maxn],sum[maxn<<2]; 9 int n; 10 11 void PushUp(int rt) 12 { 13 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 14 } 15 16 void Build(int l,int r,int rt) 17 { 18 sum[rt]=0; 19 if(l==r) return; 20 int m=(l+r)>>1; 21 Build(lson); 22 Build(rson); 23 } 24 25 void Update(int pos,int l,int r,int rt) 26 { 27 if(l==r){ 28 sum[rt]++; 29 return; 30 } 31 int m=(l+r)>>1; 32 if(pos<=m) Update(pos,lson); 33 else Update(pos,rson); 34 PushUp(rt); 35 } 36 37 int Query(int L,int R,int l,int r,int rt) 38 { 39 if(L<=l&&r<=R){ 40 return sum[rt]; 41 } 42 int res=0; 43 int m=(l+r)>>1; 44 if(L<=m) res+=Query(L,R,lson); 45 if(R>m) res+=Query(L,R,rson); 46 return res; 47 } 48 49 int main() 50 { 51 while(scanf("%d",&n)==1) 52 { 53 Build(0,n-1,1); 54 int cnt=0; 55 for (int i=0;i<n;i++) 56 { 57 cin>>a[i]; 58 cnt+=Query(a[i],n-1,0,n-1,1); 59 Update(a[i],0,n-1,1); 60 } 61 int ans=cnt; 62 for (int i=0;i<n;i++){ 63 cnt+=n-a[i]-1-a[i]; 64 ans=min(ans,cnt); 65 } 66 cout<<ans<<endl; 67 } 68 return 0; 69 } hdu 1394

HDU 2795?線段樹功能:query:區(qū)間求最大值的位置(直接把update的操作在query里做了)

這道題把h當作原來A[],相當于每一層,開始賦值都是w。所以這里也用MAX[]數(shù)組替代sum[]數(shù)組維護區(qū)間的最大值,因為層數(shù)小,能夠貼的位置先貼。

1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #define lson l,m,rt<<1 5 #define rson m+1,r,rt<<1|1 6 using namespace std; 7 const int maxn=200005; 8 int MAX[maxn<<2]; 9 int n,h,w; 10 11 void PushUp(int rt) 12 { 13 MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]); 14 } 15 16 void Build (int l,int r,int rt) 17 { 18 MAX[rt]=w; 19 if(l==r) return; 20 int m=(l+r)>>1; 21 Build(lson); 22 Build(rson); 23 } 24 25 int Query(int val,int l,int r,int rt) 26 { 27 if(l==r){ 28 MAX[rt]-=val; 29 return l; 30 } 31 int m=(l+r)>>1; 32 int res=(MAX[rt<<1]>=val)?Query(val,lson):Query(val,rson); 33 PushUp(rt); 34 return res; 35 } 36 37 int main() 38 { 39 while(scanf("%d%d%d",&h,&w,&n)==3) 40 { 41 if(h>n) h=n; 42 Build(1,h,1); 43 int x; 44 for (int i=0;i<n;i++) 45 { 46 scanf("%d",&x); 47 if(MAX[1]<x) 48 printf("-1\n"); 49 else 50 printf("%d\n",Query(x,1,h,1)); 51 } 52 } 53 return 0; 54 } hdu 2795

?

?

?

參考資料:

【1】NotOnlySuccess 【完全版】線段樹

【2】http://blog.csdn.net/zearot/article/details/52280189

【3】http://blog.csdn.net/zearot/article/details/48299459

?【4】http://www.cnblogs.com/xiaoyao24256/p/6590885.html

轉(zhuǎn)載于:https://www.cnblogs.com/zxhyxiao/p/7290153.html

總結(jié)

以上是生活随笔為你收集整理的线段树总结(一)【数据结构】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。