區間操作 樹狀陣列 線段樹

2021-10-18 16:00:02 字數 3273 閱讀 7104

涉及區間操作的一些套路必須要會呀

區間加減為了偷懶能不寫線段樹so我選擇樹狀陣列!!

但是區間乘除,最大值我想了想還是用線段樹分塊吧。

這裡用網上的一張圖:

這裡灰色陣列是原本的陣列(a[i])紅色陣列則是樹狀陣列(c[i])這裡直接給出結論:

c[i]=a[i-2^k+range[1,2^k]]

k是i的二進位制位從低到高位連續0的個數

與a[i]有關的 c[i+2^(k+j)] 且 i+2^(j+k)這樣就很好實現單點更改,區間查詢了。

void lowbit(int x)

void updata(int x,int val)//在x處加val

}int getsum(x)//求a[1~x]的和

return ans;

}

那如何進行區間查詢呢?

這裡可以用到差分陣列

比如在a=[1,5,7,2,3,7,1]則有的差分陣列d=[1,4,2,-5,1,4,-6](a[i]-a[i-1)a[0]=0,sum[d[1~i]]=a[i]

在區間x,y全部加k則可以在d[x]+k,d[y+1]-k 則在求1~i i in range[x,y]這部分區間的和即可得到a[i]+k。這樣就變成了單點修改區間查詢了

這樣實際上a陣列是沒有用的,』a『則變成了d陣列,對d陣列構造樹狀陣列c

這樣就實現了區間修改,單點查詢:

單點查詢模板

#include#include#include#includeusing namespace std;

const int n=5e5+6;

int n,m,q,p,w,x,ans,a[n],c[n];

int lowbit(int x)

void update(int x,int val)//x點+val值

}int getsum(int x)//求'a'[1~x]的和

return res;

}int main()

for(int i=1;i<=m;i++)

else

} return 0;

}

那怎麼區間修改區間查詢呢?

sum[a[1~n]]=d[1]+d[1~2]+...+d[1~n]=n*d[1]+(n-1)d[2]+...+d[n]=n*d[1~n]-(0*d[1]+1*d[2]+...+(n-1)*d[n])(在樹狀陣列裡就是另一種表示,這裡只是普通陣列表示)

可見兩部分變數可寫成=n*sum1[n]-sum2[n](又是區間求和了)

永遠要記住求誰的和構建誰的樹狀陣列然後再樹狀陣列求和,因為優化是樹狀陣列求和造成的

#include#include#include#includeusing namespace std;

const int n=5e5+6;

int n,m,q,p,w,x,ans,a[n],c1[n],c2[n];

int lowbit(int x)

void update(int x,int val)//x點+val值

}int getsum(int x)//求a[1~x]的和

res=res1-res2;//a[1~x]

return res;

}int main()

for(int i=1;i<=m;i++)

else

} return 0;

}

區間加減,乘除,最大值:

**還是過那個模板題的

#include#include#include#includeusing namespace std;

const int n=5e5+6;

int n,m,q,p,w,x,ans,a[n];

struct node

t[n*4];

void push_down(int p)

void built(int p,int l,int r)

int mid=(l+r)/2;

built(p*2,l,mid);

built(p*2+1,mid+1,r);

push_down(p);

return ;

}int askmin(int p,int qx,int zx,int gl,int gr)

int mid=(qx+zx)/2,ans=9999999;

if(gl<=mid)

ans=min(ans,askmin(p*2,qx,mid,gl,gr));

if(gr>mid)

ans=min(ans,askmin(p*2+1,mid+1,zx,gl,gr));

return ans;

} void push_tag(int p,int l,int r)

if(t[p].add)//加不會對乘的tag產生影響

return ;

}void add(int p,int qx,int zx,int gl,int gr,int k)//區間加減

int mid=(qx+zx)/2;

push_tag(p,qx,zx);

if(gl<=mid)

add(p*2,qx,mid,gl,gr,k);

if(gr>mid)

add(p*2+1,mid+1,zx,gl,gr,k);

push_down(p);

return ;

} void mult(int p,int qx,int zx,int gl,int gr,int k)//區間乘

int mid=(qx+zx)/2;

if(gl<=mid)

mult(p*2,qx,mid,gl,gr,k);

if(gr>mid)

mult(p*2+1,mid+1,zx,gl,gr,k);

}int ask(int p,int qx,int zx,int gl,int gr)

int main()

if(x==2)

} return 0;

}

區間操作 樹狀陣列 線段樹

涉及區間操作的一些套路必須要會呀 區間加減為了偷懶能不寫線段樹so我選擇樹狀陣列!但是區間乘除,最大值我想了想還是用線段樹分塊吧。這裡用網上的一張圖 這裡灰色陣列是原本的陣列 a i 紅色陣列則是樹狀陣列 c i 這裡直接給出結論 c i a i 2 k range 1,2 k k是i的二進位制位從...

區間求和(線段樹和樹狀陣列)

一.線段樹 線段樹從零開始 線段樹詳解 lazy標記思想 一種二叉樹 開四倍空間 define n 1000000 int sum n 2 求和 int a n 存原陣列 1.建樹 存和 1 遞迴實現 void pushup int rt 更新 void build int l,int r,int ...

樹狀陣列實現線段樹區間修改區間查詢功能

已知樹狀陣列區間修改單點查詢時tree陣列中存放的是相鄰差值,那麼區間修改的基礎我們已經有了,但只能支援單點查詢,需要再構造區間查詢功能,暴力累加是不可能考慮的,而樹狀陣列的區間查詢是利用字首和實現的,tree陣列中儲存的是字首和。所以我們需要在單點查詢的基礎上再構造乙個字首和。我們需要整理一下查詢...