[分块]入门题目
https://loj.ac/problems/search?keyword=%E5%88%86%E5%9D%97
https://blog.csdn.net/keepcoral/article/details/80743559
数列分块入门 1
正确解法:
简单分块,然后区间之外的暴力,区间之内的 lazy 数组标记。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <set> 7 #include <map> 8 #include <vector> 9 #include <cctype> 10 #include <sstream> 11 using namespace std; 12 typedef long long ll; 13 const int inf=0x7fffffff; 14 const int N=50000+100; 15 const int M=5000+10; 16 const double PI=acos(-1.0); 17 int n; 18 ll a[N],lazy[10000]; 19 int op,l,r,c; 20 vector<ll>buck[10000]; 21 int main() 22 { 23 scanf("%d",&n); 24 int b=sqrt(n),m=n; 25 //cout<<b<<endl; 26 for(int i=0;i<n;i++) 27 { 28 scanf("%d",&a[i]); 29 buck[i%b].push_back(a[i]); 30 } 31 while(m--) 32 { 33 scanf("%d %d %d %d",&op,&l,&r,&c); 34 if(op==0) 35 { 36 if(l>0) l--; 37 while(l<r && l%b!=0) a[l++]+=c; 38 while(l<r && r%b!=0) a[--r]+=c; 39 while(l<r) 40 { 41 int kk=l/b; 42 lazy[kk]+=c; 43 l+=b; 44 } 45 } 46 else 47 { 48 r--; 49 printf("%d\n",a[r]+lazy[r/b]); 50 } 51 } 52 53 54 return 0; 55 }
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <set> 7 #include <map> 8 #include <vector> 9 #include <cctype> 10 #include <sstream> 11 using namespace std; 12 typedef long long ll; 13 const int inf=0x7fffffff; 14 const int N=50000+100; 15 const int M=5000+10; 16 const double PI=acos(-1.0); 17 int n; 18 ll a[N],lazy[10000]; 19 int op,l,r,c; 20 vector<ll>buck[10000]; 21 int main() 22 { 23 scanf("%d",&n); 24 int b=sqrt(n),m=n; 25 //cout<<b<<endl; 26 for(int i=0;i<n;i++) 27 { 28 scanf("%d",&a[i]); 29 buck[i%b].push_back(a[i]); 30 } 31 while(m--) 32 { 33 scanf("%d %d %d %d",&op,&l,&r,&c); 34 if(op==0) 35 { 36 if(l>0) l--;//因为数组从0开始 37 while(l<r && l%b!=0) a[l++]+=c;//左边多余的 38 while(l<r && r%b!=0) a[--r]+=c;//右边多余的 39 while(l<r)//整块 40 { 41 int kk=l/b; 42 lazy[kk]+=c; 43 l+=b; 44 } 45 } 46 else 47 { 48 r--; 49 printf("%d\n",a[r]+lazy[r/b]); 50 } 51 } 52 53 54 return 0; 55 }
数列分块入门 2
正确解法:
把所有都存进数组vector里面, 然后排序,如果改变一个分块里面的部分值,就再次对块进行更新。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <set> 7 #include <map> 8 #include <vector> 9 #include <cctype> 10 #include <sstream> 11 using namespace std; 12 typedef long long ll; 13 const int inf=0x7fffffff; 14 const int N=50000+100; 15 const int M=5000+10; 16 const double PI=acos(-1.0); 17 int n; 18 ll a[N],lazy[10000]; 19 int blo[N]; 20 int op,l,r,c,b; 21 vector<ll>buck[10000]; 22 void reset(int x) 23 { 24 buck[x].clear(); 25 for(int i=(x-1)*b+1;i<=min(x*b,n);i++) 26 buck[x].push_back(a[i]); 27 sort(buck[x].begin(),buck[x].end()); 28 } 29 void add(int l,int r,int c) 30 { 31 for(int i=l;i<=min(blo[l]*b,r);i++) 32 a[i]+=c; 33 reset(blo[l]); 34 if(blo[l]!=blo[r]) 35 { 36 for(int i=(blo[r]-1)*b+1;i<=r;i++) 37 a[i]+=c; 38 reset(blo[r]); 39 } 40 for(int i=blo[l]+1;i<=blo[r]-1;i++) 41 lazy[i]+=c; 42 } 43 int query(int l,int r,int c) 44 { 45 int ans=0; 46 for(int i=l;i<=min(blo[l]*b,r);i++) 47 if(a[i]+lazy[blo[l]]<c) ans++; 48 if(blo[l]!=blo[r]) 49 { 50 for(int i=(blo[r]-1)*b+1;i<=r;i++) 51 if(a[i]+lazy[blo[r]]<c) ans++; 52 } 53 for(int i=blo[l]+1;i<=blo[r]-1;i++) 54 ans+=lower_bound(buck[i].begin(),buck[i].end(),c-lazy[i])-buck[i].begin(); 55 return ans; 56 } 57 int main() 58 { 59 scanf("%d",&n); 60 b=sqrt(n); 61 for(int i=1;i<=n;i++) 62 { 63 scanf("%lld",&a[i]); 64 blo[i]=(i-1)/b+1; 65 buck[blo[i]].push_back(a[i]); 66 } 67 for(int i=1;i<=blo[n];i++) 68 sort(buck[i].begin(),buck[i].end()); 69 for(int i=1;i<=n;i++) 70 { 71 scanf("%d %d %d %d",&op,&l,&r,&c); 72 if(op==0) add(l,r,c); 73 else 74 printf("%d\n",query(l,r,c*c)); 75 } 76 77 78 return 0; 79 }
数列分块入门 3
正确解法:
这个需要找相对应的元素,而不是元素个数,就用到了set。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <set> 7 #include <map> 8 #include <vector> 9 #include <cctype> 10 #include <sstream> 11 using namespace std; 12 typedef long long ll; 13 const int inf=0x7fffffff; 14 const int N=100000+100; 15 const int M=5000+10; 16 const double PI=acos(-1.0); 17 int n; 18 ll a[N],lazy[10000]; 19 int blo[N]; 20 int op,l,r,c,m; 21 set<ll>buck[10000]; 22 void reset(int x) 23 { 24 buck[x].clear(); 25 for(int i=(x-1)*m+1;i<=min(x*m,n);i++) 26 buck[x].insert(a[i]); 27 } 28 void add(int l,int r,int c) 29 { 30 for(int i=l;i<=min(blo[l]*m,r);i++) 31 a[i]+=c; 32 reset(blo[l]); 33 if(blo[l]!=blo[r]) 34 { 35 for(int i=(blo[r]-1)*m+1;i<=r;i++) 36 a[i]+=c; 37 reset(blo[r]); 38 } 39 for(int i=blo[l]+1;i<=blo[r]-1;i++) 40 lazy[i]+=c; 41 } 42 ll query(int l,int r,int c) 43 { 44 ll kk=-1; 45 for(int i=l;i<=min(blo[l]*m,r);i++) 46 if(a[i]+lazy[blo[l]]<c) 47 kk=max(kk,a[i]+lazy[blo[l]]); 48 if(blo[l]!=blo[r]) 49 { 50 for(int i=(blo[r]-1)*m+1;i<=r;i++) 51 if(a[i]+lazy[blo[r]]<c) 52 kk=max(kk,a[i]+lazy[blo[r]]); 53 } 54 for(int i=blo[l]+1;i<=blo[r]-1;i++) 55 { 56 set<ll>::iterator it; 57 it=buck[i].lower_bound(c-lazy[i]); 58 if(it==buck[i].begin()) continue; 59 it--; 60 kk=max(kk,(*it)+lazy[i]); 61 } 62 return kk; 63 } 64 int main() 65 { 66 scanf("%d",&n); 67 m=sqrt(n); 68 for(int i=1;i<=n;i++) 69 { 70 scanf("%lld",&a[i]); 71 blo[i]=(i-1)/m+1; 72 buck[blo[i]].insert(a[i]); 73 } 74 for(int i=1;i<=n;i++) 75 { 76 scanf("%d %d %d %d",&op,&l,&r,&c); 77 if(op==0) add(l,r,c); 78 else 79 printf("%lld\n",query(l,r,c)); 80 } 81 82 83 return 0; 84 }
数列分块入门 4
正确解法:
开一个sum数组就好了,注意的是 整个块相加是 sum[i]+lazy[i]*m;
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <set> 7 #include <map> 8 #include <vector> 9 #include <cctype> 10 #include <sstream> 11 using namespace std; 12 typedef long long ll; 13 const int inf=0x7fffffff; 14 const int N=100000+100; 15 const int M=5000+10; 16 const double PI=acos(-1.0); 17 int n; 18 ll a[N],lazy[10000],sum[10000]; 19 int blo[N]; 20 int op,l,r,c,m; 21 set<ll>buck[10000]; 22 void reset(int x) 23 { 24 buck[x].clear(); 25 for(int i=(x-1)*m+1;i<=min(x*m,n);i++) 26 buck[x].insert(a[i]); 27 } 28 void add(int l,int r,int c) 29 { 30 for(int i=l;i<=min(blo[l]*m,r);i++) 31 a[i]+=c; 32 sum[blo[l]]+=(min(blo[l]*m,r)-l+1)*c; 33 //reset(blo[l]); 34 if(blo[l]!=blo[r]) 35 { 36 for(int i=(blo[r]-1)*m+1;i<=r;i++) 37 a[i]+=c; 38 sum[blo[r]]+=(r-(blo[r]-1)*m)*c; 39 //reset(blo[r]); 40 } 41 for(int i=blo[l]+1;i<=blo[r]-1;i++) 42 lazy[i]+=c; 43 } 44 ll query(int l,int r,int c) 45 { 46 ll ans=0; 47 for(int i=l;i<=min(blo[l]*m,r);i++) 48 ans+=(a[i]+lazy[blo[l]])%c; 49 ans%=c; 50 if(blo[l]!=blo[r]) 51 { 52 for(int i=(blo[r]-1)*m+1;i<=r;i++) 53 ans+=(a[i]+lazy[blo[r]])%c; 54 ans%=c; 55 } 56 for(int i=blo[l]+1;i<=blo[r]-1;i++) 57 { 58 ans+=(sum[i]+lazy[i]*m)%c; 59 ans%=c; 60 } 61 return ans; 62 } 63 int main() 64 { 65 scanf("%d",&n); 66 m=sqrt(n); 67 for(int i=1;i<=n;i++) 68 { 69 scanf("%lld",&a[i]); 70 blo[i]=(i-1)/m+1; 71 buck[blo[i]].insert(a[i]); 72 sum[blo[i]]+=a[i]; 73 } 74 for(int i=1;i<=n;i++) 75 { 76 scanf("%d %d %d %d",&op,&l,&r,&c); 77 if(op==0) add(l,r,c); 78 else 79 printf("%lld\n",query(l,r,c+1)); 80 } 81 82 83 return 0; 84 }
数列分块入门 5
正确解法:
每个数最终都会变成0或1,我们暴力每个块,若它的最大值小于等于1,就不必再更新,否则就暴力更新。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <set> 7 #include <map> 8 #include <vector> 9 #include <cctype> 10 #include <sstream> 11 using namespace std; 12 typedef long long ll; 13 const int inf=0x7fffffff; 14 const int N=100000+100; 15 const int M=5000+10; 16 const double PI=acos(-1.0); 17 int n; 18 ll a[N],lazy[10000],sum[10000],maxx[10000]; 19 int blo[N]; 20 int op,l,r,c,m; 21 set<ll>buck[10000]; 22 void reset(int x) 23 { 24 buck[x].clear(); 25 for(int i=(x-1)*m+1;i<=min(x*m,n);i++) 26 buck[x].insert(a[i]); 27 } 28 void rset(int x) 29 { 30 sum[x]=0; 31 maxx[x]=0; 32 for(int i=(x-1)*m+1;i<=min(x*m,n);i++) 33 { 34 sum[x]+=a[i]; 35 maxx[x]=max(maxx[x],a[i]); 36 } 37 } 38 void add(int l,int r,int c) 39 { 40 for(int i=l;i<=min(blo[l]*m,r);i++) 41 a[i]=sqrt(a[i]); 42 rset(blo[l]); 43 //reset(blo[l]); 44 if(blo[l]!=blo[r]) 45 { 46 for(int i=(blo[r]-1)*m+1;i<=r;i++) 47 a[i]=sqrt(a[i]); 48 rset(blo[r]); 49 //reset(blo[r]); 50 } 51 for(int i=blo[l]+1;i<=blo[r]-1;i++) 52 if(maxx[i]>1) 53 { 54 for(int j=(i-1)*m+1;j<=i*m;j++) 55 a[j]=sqrt(a[j]); 56 rset(i); 57 } 58 } 59 ll query(int l,int r,int c) 60 { 61 ll ans=0; 62 for(int i=l;i<=min(blo[l]*m,r);i++) 63 ans+=a[i]; 64 if(blo[l]!=blo[r]) 65 { 66 for(int i=(blo[r]-1)*m+1;i<=r;i++) 67 ans+=a[i]; 68 } 69 for(int i=blo[l]+1;i<=blo[r]-1;i++) 70 { 71 ans+=sum[i]; 72 } 73 return ans; 74 } 75 int main() 76 { 77 scanf("%d",&n); 78 m=sqrt(n); 79 for(int i=1;i<=n;i++) 80 { 81 scanf("%lld",&a[i]); 82 blo[i]=(i-1)/m+1; 83 sum[blo[i]]+=a[i]; 84 maxx[blo[i]]=2; 85 } 86 for(int i=1;i<=n;i++) 87 { 88 scanf("%d %d %d %d",&op,&l,&r,&c); 89 if(op==0) add(l,r,c); 90 else 91 printf("%lld\n",query(l,r,c)); 92 } 93 94 95 return 0; 96 }
数列分块入门 6
正确解法:
1 pair<int, int> query(int a) { 2 int i = 1; 3 while (a > ve[i].size()) { 4 a -= ve[i].size(); 5 i++; 6 } 7 return make_pair(i, a - 1); 8 } 9 10 pair<int, int> t = query(b); 11 printf("%d\n", ve[t.first][t.second]);
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <queue> 6 #include <algorithm> 7 #include <vector> 8 #include <cmath> 9 #include <set> 10 #include <map> 11 #define INF 99999999 12 typedef long long ll; 13 using namespace std; 14 int v[100999]; //原数值 15 int blo[100999]; //块的数组 16 int atag[100999]; //每一个块的标记数组 17 int n, m, last; 18 int temp[200099]; 19 vector<int> ve[1009]; 20 pair<int, int> query(int a) { 21 int i = 1; 22 while (a > ve[i].size()) { 23 a -= ve[i].size(); 24 i++; 25 } 26 return make_pair(i, a - 1); 27 } 28 void reset() { 29 int top = 1, i; 30 for (i = 1; i <= last; i++) { 31 for (vector<int>::iterator it = ve[i].begin(); it != ve[i].end(); it++) { 32 temp[top++] = *it; 33 } 34 ve[i].clear(); 35 } 36 m = sqrt(top - 1); 37 for (i = 1; i <= top - 1; i++) { 38 blo[i] = (i - 1) / m + 1; 39 ve[blo[i]].push_back(temp[i]); 40 } 41 m = blo[top - 1]; 42 } 43 void insert(int a, int b) { 44 pair<int, int> t = query(a); // 45 ve[t.first].insert(ve[t.first].begin() + t.second, b); 46 if (ve[t.first].size() > m * m) 47 reset(); 48 } 49 int main() { 50 int i; 51 scanf("%d", &n); 52 m = sqrt(n); 53 for (i = 1; i <= n; i++) { 54 scanf("%d", &v[i]); 55 blo[i] = (i - 1) / m + 1; 56 ve[blo[i]].push_back(v[i]); 57 } 58 last = blo[n]; 59 for (i = 1; i <= n; i++) { 60 int op, a, b, c; 61 scanf("%d%d%d%d", &op, &a, &b, &c); 62 if (op == 0) 63 insert(a, b); 64 else { 65 pair<int, int> t = query(b); 66 printf("%d\n", ve[t.first][t.second]); 67 } 68 } 69 }
插入就用 make pair 查找位置,然后vector的动态插入。
如果某个块特别大,那就所有全部拆开重分。
数列分块入门 7
正确解法:
我们让乘法标记的优先级高于加法(如果反过来的话,新的加法标记无法处理)
若当前的一个块乘以m1后加上a1,这时进行一个乘m2的操作,则原来的标记变成m1*m2,a1*m2
若当前的一个块乘以m1后加上a1,这时进行一个加a2的操作,则原来的标记变成m1,a1+a2
如果是单独一个数的话,就把标记更新进去,然后再更新这个数。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <set> 7 #include <map> 8 #include <vector> 9 #include <cctype> 10 #include <sstream> 11 using namespace std; 12 typedef long long ll; 13 const int inf=0x7fffffff; 14 const int N=100000+100; 15 const int M=50000+10; 16 const int MOD=10007; 17 const double PI=acos(-1.0); 18 int n,m,a[N]; 19 int lazy[M],blo[N],che[M]; 20 int op,l,r,c; 21 vector<int>ve[M]; 22 void reset(int x) 23 { 24 for(int i=(blo[x]-1)*m+1;i<=min(blo[x]*m,n);i++) 25 a[i]=(a[i]*che[blo[x]]+lazy[blo[x]])%MOD; 26 che[blo[x]]=1; 27 lazy[blo[x]]=0; 28 } 29 void add(int l,int r,int c) 30 { 31 reset(l); 32 for(int i=l;i<=min(blo[l]*m,r);i++) 33 { 34 if(op==0) a[i]+=c; 35 else if(op==1) a[i]*=c; 36 a[i]%=MOD; 37 } 38 if(blo[l]!=blo[r]) 39 { 40 reset(r); 41 for(int i=(blo[r]-1)*m+1;i<=r;i++) 42 { 43 if(op==0) a[i]+=c; 44 else if(op==1) a[i]*=c; 45 a[i]%=MOD; 46 } 47 } 48 for(int i=blo[l]+1;i<=blo[r]-1;i++) 49 { 50 if(op==0) 51 { 52 lazy[i]+=c; 53 } 54 else if(op==1) 55 { 56 che[i]*=c; 57 che[i]%=MOD; 58 lazy[i]*=c; 59 lazy[i]%=MOD; 60 } 61 } 62 } 63 int query(int r) 64 { 65 return (a[r]*che[blo[r]]+lazy[blo[r]])%MOD; 66 } 67 int main() 68 { 69 scanf("%d",&n); 70 m=sqrt(n); 71 for(int i=1;i<=n;i++) 72 { 73 scanf("%d",&a[i]); 74 blo[i]=(i-1)/m+1; 75 ve[blo[i]].push_back(a[i]); 76 che[blo[i]]=1; 77 } 78 for(int i=1;i<=n;i++) 79 { 80 scanf("%d %d %d %d",&op,&l,&r,&c); 81 if(op==0||op==1) 82 add(l,r,c); 83 else 84 printf("%d\n",query(r)); 85 } 86 87 88 return 0; 89 }
数列分块入门 8
正确解法:
先把每个块标记为-1,证明里面元素都不同。
如果元素相同的话,先更新数组,然后对单个点更新。
对于整个块来说,如果每个元素都相同的话,就看是否为c,是的话 ans+=m,不是的话,标记为c
若不同的话,就暴力分析。并标记为c。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <set> 7 #include <map> 8 #include <vector> 9 #include <cctype> 10 #include <sstream> 11 using namespace std; 12 typedef long long ll; 13 const int inf=0x7fffffff; 14 const int N=100000+100; 15 const int M=50000+10; 16 const int MOD=10007; 17 const double PI=acos(-1.0); 18 int n,m,a[N]; 19 int lazy[M],blo[N],che[M]; 20 int op,l,r,c; 21 vector<int>ve[M]; 22 void reset(int x) 23 { 24 for(int i=(x-1)*m+1;i<=min(x*m,n);i++) 25 a[i]=lazy[x]; 26 lazy[x]=-1; 27 } 28 int add(int l,int r,int c) 29 { 30 int ans=0; 31 if(lazy[blo[l]]!=-1) reset(blo[l]); 32 for(int i=l;i<=min(blo[l]*m,r);i++) 33 { 34 if(a[i]==c) ans++; 35 else a[i]=c; 36 } 37 if(blo[l]!=blo[r]) 38 { 39 if(lazy[blo[r]]!=-1) reset(blo[r]); 40 for(int i=(blo[r]-1)*m+1;i<=r;i++) 41 { 42 if(a[i]==c) ans++; 43 else a[i]=c; 44 } 45 } 46 for(int i=blo[l]+1;i<=blo[r]-1;i++) 47 { 48 if(lazy[i]!=-1) 49 { 50 if(lazy[i]==c) ans+=m; 51 else lazy[i]=c; 52 } 53 else 54 { 55 for(int j=(i-1)*m+1;j<=i*m;j++) 56 { 57 if(a[j]==c) ans++; 58 else a[j]=c; 59 } 60 lazy[i]=c; 61 } 62 } 63 return ans; 64 } 65 int main() 66 { 67 scanf("%d",&n); 68 m=sqrt(n); 69 for(int i=1;i<=n;i++) 70 { 71 scanf("%d",&a[i]); 72 blo[i]=(i-1)/m+1; 73 ve[blo[i]].push_back(a[i]); 74 lazy[blo[i]]=-1; 75 } 76 for(int i=1;i<=n;i++) 77 { 78 scanf("%d %d %d",&l,&r,&c); 79 printf("%d\n",add(l,r,c)); 80 } 81 82 83 return 0; 84 }
No matter how you feel, get up , dress up , show up ,and never give up.