luogu 2801 教主的魔法

题目描述

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

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

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

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

输入输出格式

输入格式:

 

第1行为两个整数N、Q。Q为问题数与教主的施法数总和。

第2行有N个正整数,第i个数代表第i个英雄的身高。

第3到第Q+2行每行有一个操作:

(1) 若第一个字母为“M”,则紧接着有三个数字L、R、W。表示对闭区间 [L, R] 内所有英雄的身高加上W。

(2) 若第一个字母为“A”,则紧接着有三个数字L、R、C。询问闭区间 [L, R] 内有多少英雄的身高大于等于C。

 

输出格式:

 

对每个“A”询问输出一行,仅含一个整数,表示闭区间 [L, R] 内身高大于等于C的英雄数。

 

输入输出样例

输入样例#1: 复制
5 3

1 2 3 4 5

A 1 5 4

M 3 5 1

A 1 5 4
输出样例#1: 复制
2
3

说明

【输入输出样例说明】

原先5个英雄身高为1、2、3、4、5,此时[1, 5]间有2个英雄的身高大于等于4。教主施法后变为1、2、4、5、6,此时[1, 5]间有3个英雄的身高大于等于4。

【数据范围】

对30%的数据,N≤1000,Q≤1000。

对100%的数据,N≤1000000,Q≤3000,1≤W≤1000,1≤C≤1,000,000,000。

 

 

思路: 数列分块算法

由于我们要查询区间内大于等于某个数的个数,所以我们要对区间进行排序,修改的时候,如果某个块要加x,那么就给这个块直接标记+x,至于两边零散的部分,可以暴力枚举,暴力修改,修改以后排序。 

时间复杂度O(Q*sqrt(n)*logsqrt(n))=O(Q*sqrt(n)logn)  

 1 #include<bits/stdc++.h>
 2 using namespace std; 
 3 #define F(i,a,b) for(int i=a;i<=b;i++) 
 4 #define D(i,a,b) for(int i=a;i>=b;i--) 
 5 #define ms(i,a)  memset(a,i,sizeof(a)) 
 6 #define st(x)    ((x-1)*B+1)
 7 #define ed(x)    min(n,x*B)
 8 #define bl(x)    ((x-1)/B+1) 
 9 
10 int inline read(){
11     int x=0; char c=getchar(); 
12     while (c<'0' || c>'9') c=getchar(); 
13     while (c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar(); 
14     return x; 
15 }
16 
17 int const maxn=1000003;
18 int const maxm=3003; 
19 
20 int n,m,B,add[maxm],a[maxn],b[maxn],t[maxn];  
21 
22 void update(int l,int r,int z){
23     int x=bl(l); 
24     int y=bl(r); 
25     if(x==y){
26         F(i,st(x),ed(x)) t[i]=a[i];   
27         F(i,l,r) t[i]=a[i]=a[i]+z;  
28         sort(t+st(x),t+ed(x)+1);  
29         F(i,st(x),ed(x)) b[i]=t[i];  
30     }else {
31         F(i,st(x),ed(x)) t[i]=a[i];  
32         F(i,l,ed(x)) t[i]=a[i]=a[i]+z;  
33         sort(t+st(x),t+ed(x)+1); 
34         F(i,st(x),ed(x)) b[i]=t[i];  
35         F(i,st(y),ed(y)) t[i]=a[i];  
36         F(i,st(y),r) t[i]=a[i]=a[i]+z;  
37         sort(t+st(y),t+ed(y)+1); 
38         F(i,st(y),ed(y)) b[i]=t[i]; 
39         F(i,x+1,y-1) add[i]+=z;  
40     }
41 }
42 
43 int find(int l,int r,int k,int z){
44     if(b[r]+add[k]<z) return 0; 
45     int s=r;  
46     while (l<r){
47         int mid=(l+r)/2; 
48         if( b[mid]+add[k]>=z) r=mid; 
49         else l=mid+1;  
50     }
51     return s-r+1; 
52 }
53 int query(int l,int r,int z){
54     int x=bl(l); 
55     int y=bl(r); 
56     int ans=0; 
57     if(x==y){
58         F(i,l,r) if(a[i]+add[x]>=z) ans++;  
59     }else {
60         F(i,l,ed(x)) if(a[i]+add[x]>=z) ans++; 
61         F(i,st(y),r) if(a[i]+add[y]>=z) ans++;  
62         F(i,x+1,y-1) ans+=find(st(i),ed(i),i,z);  
63     }
64     return ans;  
65 }
66 
67 int main(){
68     n=read(); 
69     m=read(); 
70     F(i,1,n) a[i]=b[i]=read();  
71     B=(int)sqrt(n); 
72     F(i,1,bl(n)) sort(b+st(i),b+ed(i)+1);            
73     while (m--){
74         char s[3]; scanf("%s",s); 
75         int x=read(); 
76         int y=read(); 
77         int z=read(); 
78         if(x>y) swap(x,y) ; 
79         if(s[0]=='M') {
80             update(x,y,z);  
81         }else printf("%d\n",query(x,y,z));  
82     }
83     return 0; 
84 }
View Code

 

posted @ 2018-09-25 20:26  zjxxcn  阅读(143)  评论(0编辑  收藏  举报