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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

ACM入门之【线段树】

發布時間:2025/3/20 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ACM入门之【线段树】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

線段樹是算法競賽中常用的用來維護 區間信息 的數據結構。
線段樹可以在 O(logN)的時間復雜度內實現單點修改、區間修改、區間查詢(區間求和,求區間最大值,求區間最小值)等操作。

線段樹相對于樹狀數組代碼較長,但是線段樹較全面,功能性更強。

線段樹的基本分為兩類:

  • 單點修改,不需要懶標記。
    • pushup: 由子節點向上更新父節點
    • bulild: 一段區間初始化成線段樹
    • modify:修改
    • query:查詢
  • 區間修改,需要懶標記。
    • pushup: 由子節點向上更新父節點
    • pushdown: 由父節點向下更新子節點
    • bulild: 一段區間初始化成線段樹
    • modify:修改
    • query:查詢

線段樹代碼實現的兩種方法:

  • 結構體來實現,結構體內保存了各個信息。
  • 數組來實現,則需要在寫線段樹函數的時候需要額外的維護信息。

線段樹需要開四倍的原因:
我們不難看出上圖的倒數第二行最多為n,那么上面就是n-1 那么最后一行最多為2*n 故總共最多為4*n-1



下面我們來具體的看一下線段樹代碼實現的兩種方法:

用結構體來實現線段樹:

#include<bits/stdc++.h> using namespace std; const int N=1e5*5+10; struct node{int l,r,sum;}tr[N*4];// sum表示 [l,r] 內的和 int n,m,a[N]; void pushup(int u) {tr[u].sum=tr[u*2].sum+tr[u*2+1].sum; } void build(int u,int l,int r) {tr[u]={l,r};if(l==r){tr[u].sum=a[l];return;//子節點}int mid=l+r>>1;build(u*2,l,mid);build(u*2+1,mid+1,r);pushup(u); } void modify(int u,int x,int v) {if(tr[u].l==x&&tr[u].r==x)//子節點{tr[u].sum+=v;return;}else{int mid=(tr[u].l+tr[u].r)/2;if(x<=mid) modify(u*2,x,v);//在左邊else modify(u*2+1,x,v);//右邊pushup(u);//用子節點的信息更新父節點} } int query(int u,int l,int r) {if(l<=tr[u].l&&tr[u].r<=r) return tr[u].sum;//完全包含else{int mid=(tr[u].l+tr[u].r)/2;int sum=0;if(l<=mid) sum+=query(u*2,l,r);//與左邊有交集if(r>mid) sum+=query(u*2+1,l,r);//與右邊有交集return sum;} } int main(void) {cin>>n>>m;for(int i=1;i<=n;i++) cin>>a[i];build(1,1,n);for(int i=0;i<m;i++){int op; cin>>op;if(op==1){int x,k; cin>>x>>k;modify(1,x,k);}else {int l,r; cin>>l>>r;cout<<query(1,l,r)<<endl;}}return 0; }

數組實現線段樹:

#include<bits/stdc++.h> using namespace std; const int N=1e5*5+10; int a[N],f[N*4],n,m;//f[i]表示編號為i的區間的和 void build(int u,int l,int r) {if(l==r){f[u]=a[l];return;}int mid=l+r>>1;build(u*2,l,mid);build(u*2+1,mid+1,r);f[u]=f[u*2]+f[u*2+1]; } void add(int u,int l,int r,int x,int v) {f[u]+=v;if(l==r) return;int mid=l+r>>1;if(x<=mid) add(u*2,l,mid,x,v);else add(u*2+1,mid+1,r,x,v); } int query(int u,int l,int r,int l1,int r1) {if(l==l1&&r==r1) return f[u];int mid=l+r>>1;if(mid>=r1) return query(u*2,l,mid,l1,r1);else if(l1>=mid+1) return query(u*2+1,mid+1,r,l1,r1);else{int sum=0;sum+=query(u*2,l,mid,l1,mid);sum+=query(u*2+1,mid+1,r,mid+1,r1);return sum;} } int main(void) {cin>>n>>m;for(int i=1;i<=n;i++) cin>>a[i];build(1,1,n);for(int i=0;i<m;i++){int op; cin>>op;if(op==1){int x,k; cin>>x>>k;add(1,1,n,x,k);}else{int l,r; cin>>l>>r;cout<<query(1,1,n,l,r)<<endl;}}return 0; }

總結

以上是生活随笔為你收集整理的ACM入门之【线段树】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。