分块笔记
1、分块 (区间加法,查询小于x的个数)
技巧:开vector对区间sort,注意每次暴力更新的区间需要重新把数据放入vector中。
#include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <cstdlib> #include <iomanip> #include <bitset> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <stack> #include <cmath> #include <queue> #include <list> #include <map> #include <set> #include <cassert> using namespace std; #define lson (l , mid , rt << 1) #define rson (mid + 1 , r , rt << 1 | 1) #define debug(x) cerr << #x << " = " << x << "\n"; #define pb push_back #define pq priority_queue typedef long long ll; typedef unsigned long long ull; //typedef __int128 bll; typedef pair<ll ,ll > pll; typedef pair<int ,int > pii; typedef pair<int,pii> p3; //priority_queue<int> q;//这是一个大根堆q //priority_queue<int,vector<int>,greater<int> >q;//这是一个小根堆q #define fi first #define se second //#define endl '\n' //#define R register #define OKC ios::sync_with_stdio(false);cin.tie(0) #define FT(A,B,C) for(int A=B;A <= C;++A) //用来压行 #define REP(i , j , k) for(int i = j ; i < k ; ++i) #define max3(a,b,c) max(max(a,b), c); #define min3(a,b,c) min(min(a,b), c); //priority_queue<int ,vector<int>, greater<int> >que; const ll mos = 0x7FFFFFFF; //2147483647 const ll nmos = 0x80000000; //-2147483648 const int inf = 0x3f3f3f3f; const ll inff = 0x3f3f3f3f3f3f3f3f; //18 const int mod = 1e9+7; const double esp = 1e-8; const double PI=acos(-1.0); const double PHI=0.61803399; //黄金分割点 const double tPHI=0.38196601; template<typename T> inline T read(T&x){ x=0;int f=0;char ch=getchar(); while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x=f?-x:x; } /*-----------------------showtime----------------------*/ const int maxn = 50009; ll a[maxn]; ll sum[maxn]; vector<ll>s[1009]; int belong[maxn]; int main(){ int n; scanf("%d", &n); for(int i=1; i<=n; i++) scanf("%lld", &a[i]); int block = sqrt(n); int num = n/block; if(n%block) num++; for(int i=1; i<=n; i++) { belong[i] = (i-1)/block + 1; s[belong[i]].pb(a[i]); } for(int i=1; i<=num; i++) sort(s[i].begin(),s[i].end()); int m = n; for(int i=1; i<=m; i++){ int op;scanf("%d", &op); if(op == 0){ int l,r; ll x; scanf("%d%d%lld", &l, &r, &x); int id = belong[l],le = (belong[l]-1)*block+1; if(belong[l] == belong[r]){ for(int i=l; i<=r; i++) a[i] += x; s[id].clear(); for(int i=le; i<= belong[l]*block; i++) s[id].pb(a[i]); sort(s[id].begin(),s[id].end()); continue; } for(int i=l; i<=belong[l]*block; i++) a[i] += x; s[id].clear(); for(int i=le; i<= belong[l]*block; i++) s[id].pb(a[i]); sort(s[id].begin(),s[id].end()); for(int i=belong[l]+1; i<=belong[r]-1; i++){ sum[i] += x; } int rid = belong[r],rle = (rid - 1) * block + 1; for(int i=(rid-1)*block+1; i<=r; i++) a[i]+=x; s[rid].clear(); for(int i=rle; i<=min(n, belong[r]*block) ; i++) s[rid].pb(a[i]); sort(s[belong[r]].begin(),s[belong[r]].end()); } else { int l,r; ll x; scanf("%d%d%lld", &l, &r, &x); int cnt = 0; if(belong[l] == belong[r]){ for(int i = l; i<= r; i++){ if(a[i] + sum[belong[i]] < 1ll*x*x) cnt++; } } else { for(int i=l; i<=belong[l]*block; i++) if(a[i] + sum[belong[i]] < 1ll*x*x) cnt++; for(int i=belong[l]+1; i<=belong[r]-1; i++){ cnt += lower_bound(s[i].begin(),s[i].end(), 1ll*x*x-sum[i]) - s[i].begin(); } for(int i=(belong[r]-1)*block+1; i<=r; i++) if(a[i] + sum[belong[i]] < 1ll*x*x) cnt++; } printf("%d\n", cnt); } } return 0; }
2、区间加法,区间查询
开两个标记数组,一个是sum数组,一个是add数组。
#include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <cstdlib> #include <iomanip> #include <bitset> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <stack> #include <cmath> #include <queue> #include <list> #include <map> #include <set> #include <cassert> using namespace std; #define lson (l , mid , rt << 1) #define rson (mid + 1 , r , rt << 1 | 1) #define debug(x) cerr << #x << " = " << x << "\n"; #define pb push_back #define pq priority_queue typedef long long ll; typedef unsigned long long ull; //typedef __int128 bll; typedef pair<ll ,ll > pll; typedef pair<int ,int > pii; typedef pair<int,pii> p3; //priority_queue<int> q;//这是一个大根堆q //priority_queue<int,vector<int>,greater<int> >q;//这是一个小根堆q #define fi first #define se second //#define endl '\n' //#define R register #define OKC ios::sync_with_stdio(false);cin.tie(0) #define FT(A,B,C) for(int A=B;A <= C;++A) //用来压行 #define REP(i , j , k) for(int i = j ; i < k ; ++i) #define max3(a,b,c) max(max(a,b), c); #define min3(a,b,c) min(min(a,b), c); //priority_queue<int ,vector<int>, greater<int> >que; const ll mos = 0x7FFFFFFF; //2147483647 const ll nmos = 0x80000000; //-2147483648 const int inf = 0x3f3f3f3f; const ll inff = 0x3f3f3f3f3f3f3f3f; //18 const int mod = 1e9+7; const double esp = 1e-8; const double PI=acos(-1.0); const double PHI=0.61803399; //黄金分割点 const double tPHI=0.38196601; template<typename T> inline T read(T&x){ x=0;int f=0;char ch=getchar(); while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x=f?-x:x; } /*-----------------------showtime----------------------*/ const int maxn = 50009; ll a[maxn]; ll sum[maxn]; ll add[maxn]; int belong[maxn]; int main(){ int n; scanf("%d", &n); for(int i=1; i<=n; i++) scanf("%lld", &a[i]); int block = sqrt(n); for(int i=1; i<=n; i++) { belong[i] = (i-1)/block + 1; sum[belong[i]] += a[i]; } int m = n; while(m--){ int op; scanf("%d", &op); if(op == 0){ int l,r,x; scanf("%d%d%d", &l, &r, &x); if(belong[l] == belong[r]){ for(int i=l; i<=r; i++){ a[i] += x; sum[belong[i]] += x; } continue; } for(int i=l; i <= belong[l]*block; i++){ a[i] += x; sum[belong[i]] += x; } for(int i=belong[l]+1; i<=belong[r]-1; i++){ sum[i] += block * x; add[i] += x; } for(int i=(belong[r]-1) * block + 1; i<=r; i++){ a[i]+=x; sum[belong[i]] += x; } } else { int l,r,x; scanf("%d%d%d", &l, &r, &x); ll ans = 0; if(belong[l] == belong[r]){ for(int i=l; i<=r; i++){ ans = (ans + a[i] + add[belong[l]])%(x+1); } } else { for(int i=l; i <= belong[l]*block; i++){ ans = (ans + a[i] + add[belong[i]])%(x+1); } for(int i=belong[l]+1; i<=belong[r]-1; i++){ ans = (ans + sum[i])%(x+1); } for(int i=(belong[r]-1) * block + 1; i<=r; i++){ ans = (ans + a[i] + add[belong[i]]) %(x+1); } } printf("%lld\n", ans); } } return 0; }
3、区间开方,区间查询
由于每个数开方的次数不多,所以暴力去开方就行了,分块记录区间中为0,或1的个数。
这里 变化sum最好写成
sum[belong[i]] -= a[i]; a[i] = sqrt(a[i]); sum[belong[i]]+=a[i];
/*
int tp = a[j] - sqrt(a[j]);
a[j] = sqrt(a[j]);
sum[belong[j]]-=tp;
*/
上面这个可能有精度问题
#include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <cstdlib> #include <iomanip> #include <bitset> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <stack> #include <cmath> #include <queue> #include <list> #include <map> #include <set> #include <cassert> using namespace std; #define lson (l , mid , rt << 1) #define rson (mid + 1 , r , rt << 1 | 1) #define debug(x) cerr << #x << " = " << x << "\n"; #define pb push_back #define pq priority_queue typedef long long ll; typedef unsigned long long ull; //typedef __int128 bll; typedef pair<ll ,ll > pll; typedef pair<int ,int > pii; typedef pair<int,pii> p3; //priority_queue<int> q;//这是一个大根堆q //priority_queue<int,vector<int>,greater<int> >q;//这是一个小根堆q #define fi first #define se second //#define endl '\n' //#define R register #define OKC ios::sync_with_stdio(false);cin.tie(0) #define FT(A,B,C) for(int A=B;A <= C;++A) //用来压行 #define REP(i , j , k) for(int i = j ; i < k ; ++i) #define max3(a,b,c) max(max(a,b), c); #define min3(a,b,c) min(min(a,b), c); //priority_queue<int ,vector<int>, greater<int> >que; const ll mos = 0x7FFFFFFF; //2147483647 const ll nmos = 0x80000000; //-2147483648 const int inf = 0x3f3f3f3f; const ll inff = 0x3f3f3f3f3f3f3f3f; //18 const int mod = 1e9+7; const double esp = 1e-8; const double PI=acos(-1.0); const double PHI=0.61803399; //黄金分割点 const double tPHI=0.38196601; template<typename T> inline T read(T&x){ x=0;int f=0;char ch=getchar(); while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x=f?-x:x; } /*-----------------------showtime----------------------*/ const int maxn = 50009; ll a[maxn]; ll tot[maxn],sum[maxn]; int belong[maxn]; int main(){ int n; scanf("%d", &n); for(int i=1; i<=n; i++) scanf("%lld", &a[i]); int block = sqrt(n); for(int i=1; i<=n; i++){ belong[i] = (i-1)/block + 1; sum[belong[i]] += a[i]; if(a[i] == 1 || a[i] == 0) { tot[belong[i]]++; } } int m = n; while(m--){ int op; scanf("%d", &op); if(op == 0){ int l,r,x; scanf("%d%d%d", &l, &r, &x); if(belong[l] == belong[r]){ for(int i=l; i<=r; i++){ if(a[i] == 1 || a[i] == 0) { continue; } sum[belong[i]] -= a[i]; a[i] = sqrt(a[i]); sum[belong[i]]+=a[i]; if(a[i] == 1 || a[i] == 0) { tot[belong[i]]++; } } } else { for(int i=l; i<=belong[l]*block; i++){ if(a[i] <= 1) continue; sum[belong[i]] -= a[i]; a[i] = sqrt(a[i]); sum[belong[i]]+=a[i]; if(a[i] == 1 || a[i] == 0) { tot[belong[i]]++; } } for(int i=belong[l] + 1; i< belong[r]; i++){ if(tot[i] == block)continue; for(int j=(i-1)*block+1; j<=i*block; j++){ if(a[j] <= 1) continue; sum[belong[j]] -= a[j]; a[j] = sqrt(a[j]); sum[belong[j]]+=a[j]; if(a[j] == 1 || a[j] == 0) { tot[belong[j]]++; } } } for(int i=(belong[r]-1)*block+1; i<=r; i++){ if(a[i] <= 1) continue; sum[belong[i]] -= a[i]; a[i] = sqrt(a[i]); sum[belong[i]]+=a[i]; if(a[i] == 1 || a[i] == 0) { tot[belong[i]]++; } } } } else { int l,r,x; scanf("%d%d%d", &l, &r, &x); r = min(r, n); ll res = 0; if(belong[l] == belong[r]) { for(int i=l; i<=r; i++){ res += a[i]; } } else { for(int i=l; i<=belong[l]*block; i++){ res += a[i]; } for(int i=belong[l] + 1; i< belong[r]; i++){ res += sum[i]; } for(int i=(belong[r]-1)*block+1; i<=r; i++){ res += a[i]; } } printf("%lld\n", res); } } return 0; }
4、单点插入,单点查询
由于是插入操作,所以用动态容器做插入,比如这题用vector,然后就是由于当一个块插入过多时,可以考虑重新分块。
#include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <cstdlib> #include <iomanip> #include <bitset> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <stack> #include <cmath> #include <queue> #include <list> #include <map> #include <set> #include <cassert> using namespace std; #define lson (l , mid , rt << 1) #define rson (mid + 1 , r , rt << 1 | 1) #define debug(x) cerr << #x << " = " << x << "\n"; #define pb push_back #define pq priority_queue typedef long long ll; typedef unsigned long long ull; //typedef __int128 bll; typedef pair<ll ,ll > pll; typedef pair<int ,int > pii; typedef pair<int,pii> p3; //priority_queue<int> q;//这是一个大根堆q //priority_queue<int,vector<int>,greater<int> >q;//这是一个小根堆q #define fi first #define se second //#define endl '\n' //#define R register #define OKC ios::sync_with_stdio(false);cin.tie(0) #define FT(A,B,C) for(int A=B;A <= C;++A) //用来压行 #define REP(i , j , k) for(int i = j ; i < k ; ++i) #define max3(a,b,c) max(max(a,b), c); #define min3(a,b,c) min(min(a,b), c); //priority_queue<int ,vector<int>, greater<int> >que; const ll mos = 0x7FFFFFFF; //2147483647 const ll nmos = 0x80000000; //-2147483648 const int inf = 0x3f3f3f3f; const ll inff = 0x3f3f3f3f3f3f3f3f; //18 const int mod = 1e9+7; const double esp = 1e-8; const double PI=acos(-1.0); const double PHI=0.61803399; //黄金分割点 const double tPHI=0.38196601; template<typename T> inline T read(T&x){ x=0;int f=0;char ch=getchar(); while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x=f?-x:x; } /*-----------------------showtime----------------------*/ const int maxn = 200009; int n,block; int a[maxn],belong[maxn]; vector<ll> s[2009]; void build(){ int tot = 0; for(int i=1; i<=belong[n]; i++) { for(int j=0; j<s[i].size(); j++){ a[++tot] = s[i][j]; } s[i].clear(); } block = (int)sqrt(tot); for(int i=1; i<=tot; i++){ belong[i] = (i-1) / block + 1; s[belong[i]].pb(a[i]); } } int main(){ scanf("%d", &n); for(int i=1; i<=n; i++) scanf("%d", &a[i]); block = (int)sqrt(n); for(int i=1; i<=n; i++){ belong[i] = (i-1) / block + 1; s[belong[i]].pb(a[i]); } int m = n; while(m--){ int op; scanf("%d", &op); if(op == 0){ ll l,r,x; scanf("%lld%lld%lld", &l, &r, &x); for(int i=1; i<=belong[n]; i++){ if(s[i].size() < l) l -= (ll)s[i].size(); else { s[i].insert(s[i].begin() + l -1 ,r); if(s[i].size() > 20 * block) build(); break; } } } else { ll l,r,x; scanf("%lld%lld%lld", &l, &r, &x); for(int i=1; i<=belong[n]; i++){ if(s[i].size() < r) r = r - (ll) s[i].size(); else { printf("%lld\n", s[i][r-1]); break; } } } } return 0; }
5、询问区间等于c的个数,每次询问把区间每个数改为c
只要这个块是同一个数,就跳过,否则直接暴力计算并修改。
开了cg【maxn】表示这个块是否统一,统一为这个c,不是就是-1;
#include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <cstdlib> #include <iomanip> #include <bitset> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <stack> #include <cmath> #include <queue> #include <list> #include <map> #include <set> #include <cassert> using namespace std; #define lson (l , mid , rt << 1) #define rson (mid + 1 , r , rt << 1 | 1) #define debug(x) cerr << #x << " = " << x << "\n"; #define pb push_back #define pq priority_queue typedef long long ll; typedef unsigned long long ull; //typedef __int128 bll; typedef pair<ll ,ll > pll; typedef pair<int ,int > pii; typedef pair<int,pii> p3; //priority_queue<int> q;//这是一个大根堆q //priority_queue<int,vector<int>,greater<int> >q;//这是一个小根堆q #define fi first #define se second //#define endl '\n' //#define R register #define OKC ios::sync_with_stdio(false);cin.tie(0) #define FT(A,B,C) for(int A=B;A <= C;++A) //用来压行 #define REP(i , j , k) for(int i = j ; i < k ; ++i) #define max3(a,b,c) max(max(a,b), c); #define min3(a,b,c) min(min(a,b), c); //priority_queue<int ,vector<int>, greater<int> >que; const ll mos = 0x7FFFFFFF; //2147483647 const ll nmos = 0x80000000; //-2147483648 const int inf = 0x3f3f3f3f; const ll inff = 0x3f3f3f3f3f3f3f3f; //18 const int mod = 1e4+7; const double esp = 1e-8; const double PI=acos(-1.0); const double PHI=0.61803399; //黄金分割点 const double tPHI=0.38196601; template<typename T> inline T read(T&x){ x=0;int f=0;char ch=getchar(); while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x=f?-x:x; } /*-----------------------showtime----------------------*/ const int maxn = 100009; int n,block; int a[maxn],belong[maxn]; int cg[maxn]; void push_down(int id){ for(int i=(id-1)*block+1; i<=min(n,id*block); i++){ a[i] = cg[id]; } cg[id] = -1; } int main(){ scanf("%d", &n); for(int i=1; i<=n; i++) scanf("%d", &a[i]); block = (int)sqrt(n); for(int i=1; i<=n; i++){ belong[i] = (i-1) / block + 1; cg[belong[i]] = -1; } int m = n; while(m--){ int l,r,c; scanf("%d%d%d", &l, &r, &c); int tot = 0; if(belong [l] == belong [r]){ int id = belong[l]; if(cg[id] >= 0) push_down(id); for(int i=l; i<=r; i++) { if(a[i] == c) tot++; a[i] = c; } } else { if(cg[belong[l]]>=0) push_down(belong[l]); for(int i=l; i<=belong[l]*block; i++){ if(a[i] == c) tot++; a[i] = c; } for(int i=belong[l]+1; i<belong[r]; i++){ if(cg[i] >= 0) { if(cg[i] == c) tot += block; cg[i] = c; } else { for(int j = (i-1) * block + 1; j<= i*block; j++){ if(a[j] == c) tot++; a[j] = c; } cg[i] = c; } } if(cg[belong[r]]>=0)push_down(belong [r]); for(int i=(belong[r]-1)*block + 1; i<=r; i++){ if(a[i] == c) tot++; a[i] = c; } } printf("%d\n", tot); } return 0; }
6、不带修改,求区间众数
块的大小开30很快。
区间的众数是每个块中的众数中的一个。
#include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <cstdlib> #include <iomanip> #include <bitset> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <stack> #include <cmath> #include <queue> #include <list> #include <map> #include <set> #include <cassert> using namespace std; #define lson (l , mid , rt << 1) #define rson (mid + 1 , r , rt << 1 | 1) #define debug(x) cerr << #x << " = " << x << "\n"; #define pb push_back #define pq priority_queue typedef long long ll; typedef unsigned long long ull; //typedef __int128 bll; typedef pair<ll ,ll > pll; typedef pair<int ,int > pii; typedef pair<int,pii> p3; //priority_queue<int> q;//这是一个大根堆q //priority_queue<int,vector<int>,greater<int> >q;//这是一个小根堆q #define fi first #define se second //#define endl '\n' //#define R register #define OKC ios::sync_with_stdio(false);cin.tie(0) #define FT(A,B,C) for(int A=B;A <= C;++A) //用来压行 #define REP(i , j , k) for(int i = j ; i < k ; ++i) #define max3(a,b,c) max(max(a,b), c); #define min3(a,b,c) min(min(a,b), c); //priority_queue<int ,vector<int>, greater<int> >que; const ll mos = 0x7FFFFFFF; //2147483647 const ll nmos = 0x80000000; //-2147483648 const int inf = 0x3f3f3f3f; const ll inff = 0x3f3f3f3f3f3f3f3f; //18 const int mod = 1e9+7; const double esp = 1e-8; const double PI=acos(-1.0); const double PHI=0.61803399; //黄金分割点 const double tPHI=0.38196601; template<typename T> inline T read(T&x){ x=0;int f=0;char ch=getchar(); while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x=f?-x:x; } /*-----------------------showtime----------------------*/ const int maxn = 1e5+9; int n,blo; int a[maxn],val[maxn],be[maxn],cnt[maxn]; int f[5090][5090]; vector<int>v[maxn]; map<int,int>mp; void pre(int x){ memset(cnt, 0, sizeof(cnt)); int mx = 0; int res; for(int i=(x-1) * blo + 1; i<=n; i++){ int t = be[i]; cnt[a[i]]++; if(cnt[a[i]] > mx || (cnt[a[i]] == mx && val[a[i]] < val[res] )){ mx = cnt[a[i]]; res = a[i]; } f[x][t] = res; } } int query(int x,int l,int r){ return upper_bound(v[x].begin(),v[x].end(),r) - lower_bound(v[x].begin(),v[x].end(),l); } int main(){ scanf("%d", &n); for(int i=1; i<=n; i++){ // scanf("%d", &a[i]); read(a[i]); } // blo = (int)sqrt(n); blo = 30; int tot = 0; for(int i=1; i<=n; i++){ be[i] = (i-1)/blo + 1; if(!mp.count(a[i])) mp[a[i]] = ++ tot; int id = mp[a[i]]; val[id] = a[i]; a[i] = id; v[id].pb(i); } for(int i=1; i<=be[n]; i++){ pre(i); } int m = n; while(m--){ int l,r; scanf("%d%d", &l, &r); int mx = 0,ans; for(int i=l; i<=min(r, be[l]*blo); i++){ int t = query(a[i], l,r); if(t > mx || (t==mx && val[a[i]] < ans)){ ans = val[a[i]]; mx = t; } } int t = query(f[be[l]+1][be[r]-1],l,r); if(t > mx || (t==mx && val[f[be[l]+1][be[r]-1]] < ans)){ ans = val[f[be[l]+1][be[r]-1]]; mx = t; } if(be[l] < be[r]){ for(int i=(be[r]-1)*blo+1; i<=r; i++){ int t = query(a[i], l,r); if(t > mx || (t==mx && val[a[i]] < ans)){ ans = val[a[i]]; mx = t; } } } printf("%d\n", ans); } return 0; }
skr