luogu P2801 教主的魔法 分块

分块算法通常能跟暴力相结合,从而在较为优秀的时间内解决一个常规方法难以解决的问题,很神奇。

我们考虑将序列分块,每个块内按照身高排序。

对于修改操作,我们对于左右的边界所在的块,排回原序后,暴力修改,再按照身高排回来。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
",vec_qry(tx,ty,tw));
112     }
113     return 0;
114 }
心之所动 且就随缘去吧
原文地址:https://www.cnblogs.com/iat14/p/10519815.html