luogu P2801 教主的魔法

题目描述

教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给XMYZ信息组每个英雄看。于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1、2、……、N。

每个人的身高一开始都是不超过1000的正整数。教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W。(虽然L=R时并不符合区间的书写规范,但我们可以认为是单独增加第L(R)个英雄的身高)

CYZ、光哥和ZJQ等人不信教主的邪,于是他们有时候会问WD闭区间 [L, R] 内有多少英雄身高大于等于C,以验证教主的魔法是否真的有效。

WD巨懒,于是他把这个回答的任务交给了你。

                                  --by luogu

http://www.luogu.org/problem/show?pid=2801



分块的模板题:

读入序列,分块存一次(也就是存了两次),块内维护大小单调,块间位置不变;

有两操作:

  1. 区间加
  2. 区间大于k的个数;

对于1:

把整块属于该区间的部分的增加做成标记;

然后对区间最左最右两段,她们可能不是一个整块,把她们的原序列一个点一个点修改,然后把这两个块清了重建;

 

对于2:

基于块内单调;

对于整块属于该区间的部分二分查找,注意查找时考虑加入块的标记;

然后对区间最左最右两段,她们可能不是一个整块,怎么办呢;

怎么办呢?

对着原序列数组相应的位置一个点一个点地判断就好了;

 

需要注意的是块内需要维护单调,

怎么维护呢?

对每个新建/重建的块排序就好了;

反正有大把时光

反正时间过得去

代码如下:

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<algorithm>
 4 using namespace std;
 5 int n,q,cut,p;
 6 int a[1000010];
 7 int brick[1010][1010];
 8 int mark[2010];
 9 void add(int ,int ,int );
10 void fin(int ,int ,int );
11 int find(int ,int );
12 int main()
13 {
14     int i,j,k,l,r,wc;
15     scanf("%d%d",&n,&q);
16     cut=(int)sqrt(n);
17     if(cut*cut<n)cut++;
18     for(i=1;i<=n;i++){
19         scanf("%d",&a[i]);
20         brick[i/cut][i%cut]=a[i];
21     }
22     for(i=0;i<=cut-1;i++)
23         sort(brick[i],brick[i]+cut);
24     for(i=1;i<=q;i++){
25         char c[10];
26         scanf("%s%d%d%d",&c,&l,&r,&wc);
27         if(c[0]=='A')
28             fin(l,r,wc);
29         else
30             add(l,r,wc);
31     }
32 }
33 void add(int l,int r,int w){
34     int bl=l/cut,br=r/cut;
35     int i,j,k,ll=l%cut,rr=r%cut;
36     for(i=0;i<=cut-1;i++){
37         brick[bl][i]=a[bl*cut+i];
38         brick[br][i]=a[br*cut+i];
39         if(bl!=br){
40             if(i>=ll){
41                 brick[bl][i]+=w;
42                 a[bl*cut+i]+=w;
43             }
44             if(i<=rr){
45                 brick[br][i]+=w;
46                 a[br*cut+i]+=w;
47             }
48         }
49         else
50             if(i>=ll&&i<=rr){
51                 brick[br][i]+=w;
52                 a[br*cut+i]+=w;
53             }
54     }
55     sort(brick[br],brick[br]+cut);
56     sort(brick[bl],brick[bl]+cut);
57     bl++;br--;
58     for(i=bl;i<=br;i++)
59         mark[i]+=w;
60     return ;
61 }
62 void fin(int l,int r,int c){
63     int ans=0,i,j,k;
64     int bl=l/cut,br=r/cut,ll=l%cut,rr=r%cut;
65     if(bl==br){
66         for(j=l;j<=r;j++)
67             if(a[j]+mark[bl]>=c)
68                 ans++;
69         printf("%d\n",ans);
70         return ;
71     }
72     for(i=ll,j=l;i<=cut-1;i++,j++)
73         if(a[j]+mark[bl]>=c)
74             ans++;
75     for(i=rr,j=r;i>=0;i--,j--)
76         if(a[j]+mark[br]>=c)
77             ans++;
78     bl++;br--;
79     for(i=bl;i<=br;i++)
80         ans+=cut-find(i,c-mark[i]);
81     printf("%d\n",ans);
82     return ;
83 }
84 int find(int num,int x){
85     int mid,L=0,R=cut-1;
86     while(L<R){
87         mid=(L+R)>>1;
88         if(brick[num][mid]<x)
89             L=mid+1;
90         else
91             R=mid; 
92     }
93     if(brick[num][L]<x)
94         L++;
95     return L;
96 }
//10 10
//1 1 1 8 6 5 3 5 2 6 
//Q 1 2 5650
//A 3 8 0
//A 6 8 4
//A 3 9 6
//A 1 6 9
//Q 3 9 2403
//A 4 7 4
//Q 2 5 3066
//A 5 7 2
//A 1 8 2
a data

 

posted @ 2017-03-16 19:08  F.W.Nietzsche  阅读(194)  评论(0编辑  收藏  举报