分块的一些题(入门)
POJ-3468 区间加和区间和查询 之前作为线段树入门写过 这次用分块写一下
区间主要就是两种情况 在同一个块or不同块。整块的区域我们只要成段更新就好了,反之暴力更新~
1 #include<cmath> 2 #include<queue> 3 #include<stack> 4 #include<cstdio> 5 #include<cstring> 6 #include<iostream> 7 #include<algorithm> 8 #define FIN freopen("input.txt","r",stdin) 9 #define ll long long 10 #define mod 1000000007 11 #define lson l,m,rt<<1 12 #define rson m+1,r,rt<<1|1 13 const int maxn = 105000+5; 14 using namespace std; 15 int q[maxn]; 16 int belong[maxn],l[maxn],r[maxn]; 17 ll sum[maxn],add[maxn]; 18 int n; 19 void build(){ 20 int block=sqrt(n); 21 if(block==0) block=1; 22 int tot=n/block; 23 if(n%block!=0)tot++; 24 for(int i=1;i<=n;i++){ 25 belong[i]=(i-1)/block+1; 26 } 27 for(int i=1;i<=tot;i++){ 28 l[i]=(i-1)*block+1; 29 r[i]=i*block; 30 for(int j=l[i];j<=(i==tot?n:r[i]);j++) 31 sum[i]+=q[j]; 32 } 33 r[tot]=n; 34 } 35 void update(int x,int y,int c){ 36 if(belong[x]==belong[y]){ 37 for(int i=x;i<=y;i++){ 38 q[i]+=c;sum[belong[x]]+=c; 39 } 40 }else { 41 for(int i=x;i<=r[belong[x]];i++){ 42 q[i]+=c;sum[belong[x]]+=c; 43 } 44 for(int i=l[belong[y]];i<=y;i++){ 45 q[i]+=c;sum[belong[y]]+=c; 46 } 47 for(int i=belong[x]+1;i<belong[y];i++) 48 add[i]+=c; 49 } 50 } 51 ll query(int x,int y){ 52 ll ans=0; 53 if(belong[x]==belong[y]){ 54 for(int i=x;i<=y;i++) 55 ans+=q[i]+add[belong[x]]; 56 return ans; 57 }else { 58 for(int i=x;i<=r[belong[x]];i++) 59 ans+=q[i]+add[belong[x]]; 60 for(int i=l[belong[y]];i<=y;i++) 61 ans+=q[i]+add[belong[y]]; 62 for(int i=belong[x]+1;i<belong[y];i++) 63 ans+=add[i]*(r[i]-l[i]+1)+sum[i]; 64 return ans; 65 } 66 67 } 68 int main() 69 { 70 #ifndef ONLINE_JUDGE 71 FIN; 72 #endif 73 int m; 74 scanf("%d %d",&n,&m); 75 for(int i=1;i<=n;i++){ 76 scanf("%d",&q[i]); 77 } 78 build(); 79 while(m--){ 80 char op[3]; 81 int l,r,c; 82 scanf("%s",op); 83 if(op[0]=='Q'){ 84 scanf("%d %d",&l,&r); 85 printf("%I64d\n",query(l,r)); 86 }else { 87 scanf("%d %d %d",&l,&r,&c); 88 update(l,r,c); 89 } 90 } 91 return 0; 92 }
POJ-2104 区间第k大 之前主席树入门写过
思路:我们分块后,块内排序,然后每次我们二分数组的下标。每次对于二分的值,check下L到R区间里值是第几大,最后更新下最大值就好了。
#include<cmath> #include<queue> #include<stack> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define FIN freopen("input.txt","r",stdin) #define ll long long #define mod 1000000007 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int maxn = 100000+5; using namespace std; int q1[maxn],q2[maxn],q3[maxn]; int belong[maxn],l[maxn],r[maxn]; int n; void build(){ int block=sqrt(n); if(block==0) block=1; int tot=n/block; if(n%block) tot++; for(int i=1;i<=n;i++){ belong[i]=(i-1)/block+1; } for(int i=1;i<=tot;i++){ l[i]=(i-1)*block+1; r[i]=i*block; if(i==tot) r[i]=n; sort(q1+l[i],q1+r[i]+1); } } int check(int L,int R,int val){ int ans=0; if(belong[L]==belong[R]){ for(int i=L;i<=R;i++) if(q2[i]<val) ans++; return ans; }else{ for(int i=L;i<=r[belong[L]];i++) if(q2[i]<val) ans++; for(int i=l[belong[R]];i<=R;i++) if(q2[i]<val) ans++; for(int i=belong[L]+1;i<belong[R];i++){ int left=l[i]; int right=r[i]; int res=0; while(left<=right){ int m=(left+right)>>1; if(q1[m]<val){ left=m+1; res=max(res,m-l[i]+1); } else right=m-1; } ans+=res; } return ans; } } int find(int L,int R,int K){ int l=1; int r=n; int ans=-(1e9+7); while(l<=r){ int m=(l+r)>>1; if(check(L,R,q3[m])<K){ ans=max(ans,q3[m]); l=m+1; } else r=m-1; } return ans; } int main() { #ifndef ONLINE_JUDGE FIN; #endif int m; scanf("%d %d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&q1[i]); q2[i]=q3[i]=q1[i]; } build(); sort(q3+1,q3+1+n); for(int i=1;i<=m;i++){ int L,R,k; scanf("%d %d %d",&L,&R,&k); printf("%d\n",find(L,R,k)); } return 0; }
思路:线段不想交,意味着后面的组成的线段斜率要比前面大即可,每次操作我们更新当前的块,然后每次我们只要求出大于等于前一块的最高值的数量,累加即可。
#include<bits/stdc++.h> #define FIN freopen("input.txt","r",stdin) #define ll long long #define mod 1000000007 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int maxn = 100000+5; using namespace std; int belong[maxn],tot; struct node{ int l,r; vector<double> v; }p[maxn]; double H[maxn]; int n,m; void build(){ int k=sqrt(n); tot=n/k; if(n%k) tot++; for(int i=1;i<=n;i++){ belong[i]=(i-1)/k+1; } for(int i=1;i<=tot;i++){ p[i].l=(i-1)*k+1; p[i].r=i*k; } p[tot].r=n; } int solve(int x,int h){ int to=belong[x]; H[x]=1.0*h/x; double mx=0.0; p[to].v.clear(); for(int i=p[to].l;i<=p[to].r;i++){ if(H[i]>mx){ mx=H[i]; p[to].v.push_back(H[i]); } } mx=0.0; int ans=0; for(int i=1;i<=tot;i++){ if(p[i].v.size()==0) continue; ans+=p[i].v.end()-upper_bound(p[i].v.begin(),p[i].v.end(),mx); mx=max(mx,*p[i].v.rbegin()); } return ans; } int main() { #ifndef ONLINE_JUDGE FIN; #endif scanf("%d %d",&n,&m); build(); for(int i=1;i<=m;i++){ int x,h; scanf("%d %d",&x,&h); printf("%d\n",solve(x,h)); } }