分块入门(根据hzwer的博客。。)(右端点是r不是n。。)
生活随笔
收集整理的這篇文章主要介紹了
分块入门(根据hzwer的博客。。)(右端点是r不是n。。)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
1.區(qū)間更新單點查詢
#include <bits/stdc++.h> using namespace std; #define ll long long #define maxn 100005 int n, len, pos[maxn], a[maxn]; struct Block {int add; } b[1000]; void update(int l, int r, int c) {int p = pos[l], q = pos[r];if (p == q)for (int i = l; i <= r; i++) a[i] += c;else {for (int i = p + 1; i <= q - 1; i++) b[i].add += c;for (int i = l; i <= p * len; i++) a[i] += c;for (int i = (q - 1) * len + 1; i <= r; i++) a[i] += c;} } int main() {cin >> n;len = sqrt(n);for (int i = 1; i <= n; i++) cin >> a[i];for (int i = 1; i <= n; i++) pos[i] = (i - 1) / len + 1;int opt, l, r, c;for (int i = 1; i <= n; i++) {scanf("%d%d%d%d", &opt, &l, &r, &c);if (opt == 0)update(l, r, c);elsecout << a[r] + b[pos[r]].add << '\n';} }2.區(qū)間求小于c的數(shù)的個數(shù):先預處理,即把每塊的元素sort一下,整塊修改用add標記,查詢用lower_bound,兩端修改后用sort維護,查詢暴力統(tǒng)計即可
注意要把add當做塊的屬性,而不要下放到塊中的元素里去
/* 預處理塊時需要將塊內元素進行排序,然后可以每次查詢都是用二分來做 區(qū)間更新時要將兩端元素進行單獨修改+排序 */ #include <bits/stdc++.h> using namespace std; #define ll long long #define maxn 50005 struct Block {int add;vector<int> v; } b[5005]; int n, pos[maxn], len; int a[maxn];inline void calc(int p) {b[p].v.clear();for (int i = (p - 1) * len + 1; i <= min(p * len, n); i++) b[p].v.push_back(a[i]);sort(b[p].v.begin(), b[p].v.end()); } void update(int l, int r, int c) {int p = pos[l], q = pos[r];if (p == q) {for (int i = l; i <= r; i++) a[i] += c;calc(p);return;}for (int i = p + 1; i <= q - 1; i++) b[i].add += c;for (int i = l; i <= min(p * len, n); i++) a[i] += c;for (int i = (q - 1) * len + 1; i <= r; i++) a[i] += c;calc(p);calc(q); } int query(int l, int r, int c) {int res = 0;int p = pos[l], q = pos[r];if (p == q) {for (int i = l; i <= r; i++)if (a[i] + b[p].add < c)res++;return res;}for (int i = p + 1; i <= q - 1; i++) {int x = c - b[i].add;int tmp = lower_bound(b[i].v.begin(), b[i].v.end(), x) - b[i].v.begin();res += tmp;}for (int i = l; i <= min(p * len, n); i++)if (a[i] + b[p].add < c)res++;for (int i = (q - 1) * len + 1; i <= r; i++)if (a[i] + b[q].add < c)res++;return res; } int main() {cin >> n;len = sqrt(n);for (int i = 1; i <= n; i++) cin >> a[i];for (int i = 1; i <= n; i++) {pos[i] = (i - 1) / len + 1;b[pos[i]].v.push_back(a[i]);}for (int i = 1; i <= pos[n]; i++) //預處理先排序 sort(b[i].v.begin(), b[i].v.end());int m = n;while (m--) {ll opt, l, r, c;scanf("%d%d%d%d", &opt, &l, &r, &c);if (opt == 0)update(l, r, c);elsecout << query(l, r, c * c) << endl;} }3.區(qū)間更新+找區(qū)間內小于c的最大的數(shù)(c的前驅)
塊設為sqrt(n)就會t,設為1000就沒事。。玄學復雜度啊
/* set每次修改都是logn,那么n次塊內更新耗時n*sqrt(n)*logsqrt(n) */ #include <bits/stdc++.h> using namespace std; #define maxn 100005 struct Block {int add;set<int> s; } b[1005]; int n, pos[maxn], len, a[maxn]; set<int>::iterator it;void update(int l, int r, int c) {int p = pos[l], q = pos[r];if (p == q) {for (int i = l; i <= r; i++) {b[p].s.erase(a[i]);a[i] += c;b[p].s.insert(a[i]);}return;}for (int i = p + 1; i <= q - 1; i++) b[i].add += c;for (int i = l; i <= min(p * len, n); i++) {b[p].s.erase(a[i]);a[i] += c;b[p].s.insert(a[i]);}for (int i = (q - 1) * len + 1; i <= r; i++) {b[q].s.erase(a[i]);a[i] += c;b[q].s.insert(a[i]);} } int query(int l, int r, int c) {int res = -1, p = pos[l], q = pos[r];if (p == q) {for (int i = l; i <= r; i++) {int x = a[i] + b[p].add;if (x < c)res = max(res, x);}return res;}for (int i = p + 1; i <= q - 1; i++) { //大塊里用set查int x = c - b[i].add;it = b[i].s.lower_bound(x);if (it == b[i].s.begin())continue;it--;res = max(res, (*it) + b[i].add);}for (int i = l; i <= min(p * len, n); i++)if (a[i] + b[p].add < c)res = max(res, a[i] + b[p].add);for (int i = (q - 1) * len + 1; i <= r; i++)if (a[i] + b[q].add < c)res = max(res, a[i] + b[q].add);return res; }int main() {cin >> n;len = 1500;for (int i = 1; i <= n; i++) scanf("%d", &a[i]);for (int i = 1; i <= n; i++) {pos[i] = (i - 1) / len + 1;b[pos[i]].s.insert(a[i]);}for (int i = 1; i <= n; i++) {int opt, l, r, c;scanf("%d%d%d%d", &opt, &l, &r, &c);if (opt == 0)update(l, r, c);elsecout << query(l, r, c) << endl;} }4.區(qū)間更新,區(qū)間求和
#include <bits/stdc++.h> using namespace std; #define ll long long #define maxn 50005 struct Block {ll add, sum; } b[500]; int n, pos[maxn], len; ll a[maxn];void update(int l, int r, int c) {int p = pos[l], q = pos[r];if (p == q) {for (int i = l; i <= r; i++) a[i] += c, b[p].sum += c;return;}for (int i = p + 1; i <= q - 1; i++) b[i].add += c;for (int i = l; i <= min(p * len, n); i++) a[i] += c, b[p].sum += c;for (int i = (q - 1) * len + 1; i <= r; i++) a[i] += c, b[q].sum += c; } ll query(int l, int r, int c) {ll res = 0;int p = pos[l], q = pos[r];if (p == q) {for (int i = l; i <= r; i++) res += a[i] + b[p].add;return res % c;}for (int i = p + 1; i <= q - 1; i++) res += b[i].sum, res += len * b[i].add;for (int i = l; i <= min(p * len, n); i++) res += b[p].add, res += a[i];for (int i = (q - 1) * len + 1; i <= r; i++) res += b[q].add, res += a[i];return res % c; }int main() {cin >> n;len = sqrt(n);for (int i = 1; i <= n; i++) cin >> a[i];for (int i = 1; i <= n; i++) {pos[i] = (i - 1) / len + 1;b[pos[i]].sum += a[i];}for (int i = 1; i <= n; i++) {int opt, l, r, c;scanf("%d%d%d%d", &opt, &l, &r, &c);if (opt == 0)update(l, r, c);elsecout << query(l, r, c + 1) << endl;} }?5.區(qū)間開根(類似于勢能線段樹)
/* 2*2=4,4*4=16,16*16=256,每個數(shù)最多被開4次,開了4次以上就是1 所以兩端暴力開,整塊判斷塊中所有元素是不是1,是的話那么這個塊就不用開了 修改最多4n,查詢就是n*根號n */ #include <bits/stdc++.h> using namespace std; #define maxn 50005 struct Block {int flag;int sum; } b[500]; int n, len, pos[maxn], a[maxn];void calc(int p) {if (b[p].flag)return;b[p].flag = 1;b[p].sum = 0;for (int i = (p - 1) * len + 1; i <= p * len; i++) {a[i] = (int)sqrt(a[i]);b[p].sum += a[i];if (a[i] > 1)b[p].flag = 0;} } void update(int l, int r) {int p = pos[l], q = pos[r];if (p == q) {for (int i = l; i <= r; i++) {b[p].sum -= a[i];a[i] = sqrt(a[i]);b[p].sum += a[i];}return;}for (int i = p + 1; i <= q - 1; i++) calc(i);for (int i = l; i <= min(r, p * len); i++) {b[p].sum -= a[i];a[i] = sqrt(a[i]);b[p].sum += a[i];}for (int i = (q - 1) * len + 1; i <= r; i++) {b[q].sum -= a[i];a[i] = sqrt(a[i]);b[q].sum += a[i];} } int query(int l, int r) {int res = 0, p = pos[l], q = pos[r];if (p == q) {for (int i = l; i <= r; i++) res += a[i];return res;}for (int i = p + 1; i <= q - 1; i++) res += b[i].sum;for (int i = l; i <= min(p * len, r); i++) res += a[i];for (int i = (q - 1) * len + 1; i <= r; i++) res += a[i];return res; }int main() {cin >> n;len = sqrt(n);for (int i = 1; i <= n; i++) cin >> a[i];for (int i = 1; i <= n; i++) {pos[i] = (i - 1) / len + 1;b[pos[i]].sum += a[i];}for (int i = 1; i <= n; i++) {int opt, l, r, c;cin >> opt >> l >> r >> c;if (opt == 0)update(l, r);elsecout << query(l, r) << endl;} }6.塊狀數(shù)組,塊狀鏈表:用來解決在數(shù)列中插入一個數(shù)
/* 塊內維護一個數(shù)組和size 再用前綴和log根號n 的時間內找到新來的數(shù)應該加在哪個塊中 然后每增加一個數(shù)都要消耗該數(shù)所在塊的長度的時間 如果數(shù)據隨機,那么一次插入就是O(根號n)如果不隨機。。可能n個數(shù)都加在同一個塊內,那么會導致復雜度退化為n^2 那么當塊過大時進行重構即可,這里將塊大小上限設置為20*根號n */ #include<bits/stdc++.h> #include<vector> using namespace std; #define maxn 200005 struct Block{vector<int>v; }b[20005]; int nn,n,len,m,pos[maxn],a[maxn];//塊的長度,塊的個數(shù) void rebuild(){nn=0;for(int i=1;i<=m;i++){for(int j=0;j<b[i].v.size();j++)a[++nn]=b[i].v[j];b[i].v.clear();}len=sqrt(nn);m=(nn-1)/len+1;for(int i=1;i<=nn;i++){pos[i]=(i-1)/len+1;b[pos[i]].v.push_back(a[i]);} } void update(int pos,int x){//在位置pos插入x int p=1;while(b[p].v.size()<pos)pos-=b[p].v.size(),p++;b[p].v.insert(b[p].v.begin()+pos-1,x);if(b[p].v.size()>20*len)rebuild(); } int query(int pos){int p=1;while(b[p].v.size()<pos)pos-=b[p].v.size(),p++;return b[p].v[pos-1]; } int main(){cin>>n;len=sqrt(n);for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++){pos[i]=(i-1)/len+1;b[pos[i]].v.push_back(a[i]);}m=pos[n];for(int i=1;i<=n;i++){int opt,l,r,c;cin>>opt>>l>>r>>c;if(opt==0)update(l,r);else cout<<query(r)<<endl;} }?7.標記下傳順序(標記優(yōu)先級)
/* 把數(shù)字表示成a*mul+add的形式 */ #include<bits/stdc++.h> using namespace std; #define maxn 100005 #define mod 10007 #define ll long long struct Block{int mul,add; }b[1005]; int a[maxn],n,len,pos[maxn];void pushdown(int p){for(int i=(p-1)*len+1;i<=min(p*len,n);i++)a[i]=((ll)a[i]*b[p].mul+b[p].add)%mod;b[p].add=0;b[p].mul=1; }/* void add(int l,int r,int c){int p=pos[l],q=pos[r];if(p==q){pushdown(p);for(int i=l;i<=r;i++)a[i]=(a[i]+c)%mod;return; }for(int i=p+1;i<=q-1;i++)b[i].add=(b[i].add+(ll)b[i].mul*c)%mod;pushdown(p);pushdown(q);for(int i=l;i<=min(p*len,r);i++)a[i]=(a[i]+c)%mod;for(int i=(q-1)*len+1;i<=r;i++)a[i]=(a[i]+c)%mod; } void mul(int l,int r,int c){int p=pos[l],q=pos[r];if(p==q){pushdown(p);for(int i=l;i<=r;i++)a[i]=((ll)a[i]*c)%mod;return;}for(int i=p+1;i<=q-1;i++){b[i].mul=((ll)b[i].mul*c)%mod;b[i].add=((ll)b[i].add*c)%mod;}pushdown(p);pushdown(q);for(int i=1;i<=min(p*len,r);i++)a[i]=((ll)a[i]*c)%mod;for(int i=(q-1)*len+1;i<=r;i++)a[i]=((ll)a[i]*c)%mod; }*/ void update(int f,int l,int r,int c){int p=pos[l],q=pos[r];pushdown(p);for(int i=l;i<=min(r,p*len);i++){if(f==0)a[i]+=c;else a[i]*=c;a[i]%=mod;}if(p!=q){pushdown(q);for(int i=(q-1)*len+1;i<=r;i++){if(f==0)a[i]+=c;else a[i]*=c;a[i]%=mod;} }for(int i=p+1;i<=q-1;i++){if(f==0)b[i].add=(b[i].add+c)%mod;else {b[i].mul=(b[i].mul*c)%mod;b[i].add=(b[i].add*c)%mod;}} } int query(int x){int p=pos[x];return ((ll)a[x]*b[p].mul+b[p].add)%mod; } int main(){cin>>n;len=sqrt(n);for(int i=1;i<=n;i++)scanf("%d",&a[i]);for(int i=1;i<=n;i++)pos[i]=(i-1)/len+1;for(int i=1;i<=pos[n];i++)b[i].mul=1;for(int i=1;i<=n;i++){int opt,l,r,c;scanf("%d%d%d%d",&opt,&l,&r,&c);if(opt==2)cout<<query(r)<<endl;else update(opt,l,r,c);} }?8.區(qū)間覆蓋
/* 區(qū)間眾數(shù) 覆蓋標記*/ #include<bits/stdc++.h> using namespace std; #define maxn 100005 struct Block{int c; }b[500]; int a[maxn],n,pos[maxn],len; void pushdown(int p){if(b[p].c!=-1){for(int i=(p-1)*len+1;i<=p*len;i++)a[i]=b[p].c;b[p].c=-1;} } int query(int l,int r,int c){int res=0,p=pos[l],q=pos[r];if(p==q){pushdown(p);for(int i=l;i<=r;i++)if(a[i]==c)res++;else a[i]=c;return res;} pushdown(p);pushdown(q);for(int i=l;i<=min(p*len,r);i++)if(a[i]==c)res++;else a[i]=c;for(int i=(q-1)*len+1;i<=r;i++)if(a[i]==c)res++;else a[i]=c;for(int i=p+1;i<=q-1;i++)if(b[i].c!=-1){if(b[i].c==c)res+=len;else b[i].c=c;}else {for(int j=(i-1)*len+1;j<=i*len;j++)if(a[j]==c)res++;else a[j]=c;b[i].c=c;}return res; }int main(){cin>>n;len=sqrt(n);for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++)pos[i]=(i-1)/len+1,b[pos[i]].c=-1;for(int i=1;i<=n;i++){int l,r,c;cin>>l>>r>>c;cout<<query(l,r,c)<<endl;} }?
轉載于:https://www.cnblogs.com/zsben991126/p/10575330.html
總結
以上是生活随笔為你收集整理的分块入门(根据hzwer的博客。。)(右端点是r不是n。。)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Javascript面向对象研究心得
- 下一篇: jquery控制css的display(