涉及區間操作的一些套路必須要會呀
區間加減為了偷懶能不寫線段樹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陣列中儲存的是字首和。所以我們需要在單點查詢的基礎上再構造乙個字首和。我們需要整理一下查詢...