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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

线段树初见——区间询问与改变最大值

發(fā)布時(shí)間:2023/12/3 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 线段树初见——区间询问与改变最大值 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

昨天某B組講主席樹,然后就作死的去聽了,也沒聽懂(因?yàn)檫B線段樹都不懂),然后好奇心就去問了一下老師線段樹是個(gè)蛤,然后這篇博客就誕生了。

正題

首先線段樹就是一個(gè)可以快速區(qū)間改變和詢問的東東,實(shí)現(xiàn)方法就是用樹啦。具體方法看下面。


首先我們講一下例題:

最大值(jzoj1959)

一串序列,有2種操作

1.詢問一個(gè)區(qū)間內(nèi)的最大值
2.改變一個(gè)數(shù)的值

這道題明顯沒有用到區(qū)間改值,那這里先不扯區(qū)間改值:
以下線段樹草圖

每個(gè)點(diǎn)表示的是一個(gè)區(qū)間內(nèi)的樹
建樹代碼

int build(int l,int r,int k) {if (l==r) return tree[k].w=a[l];//如果只有一個(gè)數(shù)就直接返回int wz=(l+r)/2;//中間位置return tree[k].w=max(build(l,wz,2*k),build(wz+1,r,2*k+1));//分叉 }

然后是查找某區(qū)間
草圖

分成多份尋找需要的區(qū)間
查找代碼

void find(int l,int r,int x,int y,int k)//表示在l~r之間需要x~y的最大值 {if (x==l && y==r) {ans=max(ans,tree[k].w);return;}int wz=(l+r)/2;//中心if (y<=wz) find(l,wz,x,y,2*k);//需要全包涵在左邊else if (x>wz) find(wz+1,r,x,y,2*k+1);//需要全包涵在右邊else {find(l,wz,x,wz,2*k);find(wz+1,r,wz+1,y,2*k+1);//有左也有右}return; }

然后由于這道題只需要改變單個(gè)數(shù)的,瞎水水就過了
代碼

#include<cstdio> #include<iostream> using namespace std; struct point{int w,lazy; }tree[400014]; int n,m,w,x,y,a[100007],ans; int build(int l,int r,int k)//建數(shù) {if (l==r) return tree[k].w=a[l];int wz=(l+r)/2;return tree[k].w=max(build(l,wz,2*k),build(wz+1,r,2*k+1)); } void find(int l,int r,int x,int y,int k)//查找 {if (x==l && y==r) {ans=max(ans,tree[k].w);return;}int wz=(l+r)/2;if (y<=wz) find(l,wz,x,y,2*k);else if (x>wz) find(wz+1,r,x,y,2*k+1);else {find(l,wz,x,wz,2*k);find(wz+1,r,wz+1,y,2*k+1);}return; } void updata(int l,int r,int x,int y,int k)//改變 {if (l==x && r==x) {tree[k].w=y;return;}//改變并返回int wz=(l+r)/2;//確定位置if (x<=wz) updata(l,wz,x,y,2*k);//在左邊else if (x>wz) updata(wz+1,r,x,y,2*k+1);//在右邊tree[k].w=max(tree[2*k].w,tree[2*k+1].w);//更新值 } int main() {scanf("%d",&n);for (int i=1;i<=n;i++) scanf("%d",&a[i]);build(1,n,1);//建樹scanf("%d",&m);for (int i=1;i<=m;i++){scanf("%d",&w);if (w==2){scanf("%d%d",&x,&y);ans=0;find(1,n,x,y,1);//查找printf("%d\n",ans);}else if (w==1){scanf("%d%d",&x,&y);updata(1,n,x,y,1);//改變}} }

最大值2(jzoj1960)

依舊是一個(gè)序列兩種操作

1.詢問一個(gè)區(qū)間內(nèi)的值
2.讓一個(gè)區(qū)間內(nèi)的值加上一個(gè)數(shù)(可能是負(fù)數(shù))

這里就需要用到區(qū)間改變了

像查找一樣,找到區(qū)間,如果直接改變整棵子樹會(huì)超時(shí),所以先標(biāo)記,查找時(shí)在下傳

好了,區(qū)間改變代碼

void updata(int l,int r,int x,int y,int num,int k) {if (l==x && r==y) {tree[k].lazy+=num;//標(biāo)記tree[k].w+=num;//改變自己return;}if (tree[k].lazy!=0)//順便下傳{tree[k*2].w+=tree[k].lazy;tree[k*2].lazy+=tree[k].lazy;tree[k*2+1].w+=tree[k].lazy;tree[k*2+1].lazy+=tree[k].lazy; tree[k].lazy=0;}int wz=(l+r)/2;//中心if (y<=wz) updata(l,wz,x,y,num,2*k);else if (x>wz) updata(wz+1,r,x,y,num,2*k+1);else {updata(l,wz,x,wz,num,2*k);updata(wz+1,r,wz+1,y,num,2*k+1);}tree[k].w=max(tree[2*k].w,tree[2*k+1].w);//更新 }

代碼

#include<cstdio> #include<iostream> using namespace std; struct point{long long w,lazy; }tree[400030]; long long ans; int n,m,w,x,y,a[100007],num; int build(int l,int r,int k)//建樹 {if (l==r) return tree[k].w=a[l];int wz=(l+r)/2;return tree[k].w=max(build(l,wz,2*k),build(wz+1,r,2*k+1)); } void find(int l,int r,int x,int y,int k)//查找 {if (x==l && y==r) {ans=max(ans,tree[k].w);return;}if (tree[k].lazy!=0){tree[k*2].w+=tree[k].lazy;tree[k*2].lazy+=tree[k].lazy;tree[k*2+1].w+=tree[k].lazy;tree[k*2+1].lazy+=tree[k].lazy; tree[k].lazy=0;}int wz=(l+r)/2;if (y<=wz) find(l,wz,x,y,2*k);else if (x>wz) find(wz+1,r,x,y,2*k+1);else {find(l,wz,x,wz,2*k);find(wz+1,r,wz+1,y,2*k+1);} } void updata(int l,int r,int x,int y,int num,int k)//改值 {if (l==x && r==y) {tree[k].lazy+=num;tree[k].w+=num;return;}if (tree[k].lazy!=0){tree[k*2].w+=tree[k].lazy;tree[k*2].lazy+=tree[k].lazy;tree[k*2+1].w+=tree[k].lazy;tree[k*2+1].lazy+=tree[k].lazy; tree[k].lazy=0;}int wz=(l+r)/2;if (y<=wz) updata(l,wz,x,y,num,2*k);else if (x>wz) updata(wz+1,r,x,y,num,2*k+1);else {updata(l,wz,x,wz,num,2*k);updata(wz+1,r,wz+1,y,num,2*k+1);}tree[k].w=max(tree[2*k].w,tree[2*k+1].w); } int main() {scanf("%d",&n);for (int i=1;i<=n;i++) scanf("%d",&a[i]);build(1,n,1);scanf("%d",&m);for (int i=1;i<=m;i++){scanf("%d",&w);if (w==2){scanf("%d%d",&x,&y);//查找ans=-2147483647;find(1,n,x,y,1);printf("%lld\n",ans);}else if (w==1){scanf("%d%d%d",&x,&y,&num);//改值updata(1,n,x,y,num,1);}} } 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

總結(jié)

以上是生活随笔為你收集整理的线段树初见——区间询问与改变最大值的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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