分块算法通常能跟暴力相结合,从而在较为优秀的时间内解决一个常规方法难以解决的问题,很神奇。
我们考虑将序列分块,每个块内按照身高排序。
对于修改操作,我们对于左右的边界所在的块,排回原序后,暴力修改,再按照身高排回来。O(sqrt(n)logn)。对于中间的整块,打一个标记来修改。O(sqrt(n))。
对于询问操作,我们对于左右的边界所在的快,排回原序后,暴力查询,再按照身高排回来。O(sqrt(n)logn)。对于中间的整块,因为每一块都有序,所以我们对于每一块二分查找下,多少个人身高不低于c,别忘记把标记算上,二分边界情况也处理好,被二分边界卡了一个点想了半天。O(sqrt(n)logn)。
所以总的复杂度为O(q sqrt(n) logn),开完O2勉强跑过。
1 #include <cstdio> 2 #include <algorithm> 3 #include <cmath> 4 using namespace std; 5 struct pot 6 { 7 int h,id; 8 } vec[1001000]; 9 int add[1001000]; 10 int n,q,blk; 11 bool cmp1(pot a,pot b) 12 { 13 return a.h < b.h; 14 } 15 bool cmp2(pot a,pot b) 16 { 17 return a.id < b.id; 18 } 19 void vec_add(int x,int y,int w) 20 { 21 int lbn = (x - 1) / blk + 1; 22 int rbn = (y - 1) / blk + 1; 23 int lbb = (lbn - 1) * blk + 1; 24 int lbe = min(lbn * blk,n); 25 int rbb = (rbn - 1) * blk + 1; 26 int rbe = min(rbn * blk,n); 27 if (lbn == rbn) 28 { 29 sort(vec + lbb,vec + lbe + 1,cmp2); 30 for (int i = x;i <= y;i++) 31 vec[i].h += w; 32 sort(vec + lbb,vec + lbe + 1,cmp1); 33 } 34 // 35 sort(vec + lbb,vec + lbe + 1,cmp2); 36 for (int i = x;i <= lbe;i++) 37 vec[i].h += w; 38 sort(vec + lbb,vec + lbe + 1,cmp1); 39 // 40 sort(vec + rbb,vec + rbe + 1,cmp2); 41 for (int i = rbb;i <= y;i++) 42 vec[i].h += w; 43 sort(vec + rbb,vec + rbe + 1,cmp1); 44 // 45 for (int i = lbn + 1;i <= rbn - 1;i++) 46 add[i] += w; 47 } 48 int vec_qry(int x,int y,int c) 49 { 50 int res = 0; 51 int lbn = (x - 1) / blk + 1; 52 int rbn = (y - 1) / blk + 1; 53 int lbb = (lbn - 1) * blk + 1; 54 int lbe = min(lbn * blk,n); 55 int rbb = (rbn - 1) * blk + 1; 56 int rbe = min(rbn * blk,n); 57 if (lbn == rbn) 58 { 59 sort(vec + lbb,vec + lbe + 1,cmp2); 60 for (int i = x;i <= y;i++) 61 res += vec[i].h + add[lbn] >= c ? 1 : 0; 62 sort(vec + lbb,vec + lbe + 1,cmp1); 63 return res; 64 } 65 // 66 sort(vec + lbb,vec + lbe + 1,cmp2); 67 for (int i = x;i <= lbe;i++) 68 res += vec[i].h + add[lbn] >= c ? 1 : 0; 69 sort(vec + lbb,vec + lbe + 1,cmp1); 70 // 71 sort(vec + rbb,vec + rbe + 1,cmp2); 72 for (int i = rbb;i <= y;i++) 73 res += vec[i].h + add[rbn] >= c ? 1 : 0; 74 sort(vec + rbb,vec + rbe + 1,cmp1); 75 // 76 for (int i = lbn + 1;i <= rbn - 1;i++) 77 { 78 int l = (i - 1) * blk + 1,r = i * blk,mid; 79 while (l < r) 80 { 81 mid = l + r >> 1; 82 if (vec[mid].h + add[i] >= c) 83 r = mid; 84 else 85 l = mid + 1; 86 } 87 res += i * blk - l + 1; 88 if (vec[l].h + add[i] < c) res--; 89 } 90 return res; 91 } 92 int main() 93 { 94 scanf("%d%d",&n,&q); 95 blk = sqrt(n); 96 for (int i = 1;i <= n;i++) 97 { 98 scanf("%d",&vec[i].h); 99 vec[i].id = i; 100 } 101 for (int i = 1;i <= n;i += blk) 102 sort(vec + i,vec + min(n,i + blk - 1) + 1,cmp1); 103 int tx,ty,tw; 104 char str[10]; 105 for (int i = 1;i <= q;i++) 106 { 107 scanf("%s%d%d%d",str,&tx,&ty,&tw); 108 if (str[0] == 'M') 109 vec_add(tx,ty,tw); 110 else 111 printf("%d\n",vec_qry(tx,ty,tw)); 112 } 113 return 0; 114 }