[Noip模拟题]教主的魔法

烂漫一生 提交于 2020-07-27 11:42:32

[Noip模拟题]教主的魔法

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 129  Solved: 57

Description

教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给XMYZ信息组每个英雄看。于是N个英雄们又一
次聚集在了一起,这次他们排成了一列,被编号为1、2、……、N。每个人的身高一开始都是不超过1000的正整数
。教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W。(虽然L=R时并不符合
区间的书写规范,但我们可以认为是单独增加第L(R)个英雄的身高)CYZ、光哥和ZJQ等人不信教主的邪,于是他
们有时候会问WD闭区间 [L, R] 内有多少英雄身高大于等于C,以验证教主的魔法是否真的有效。WD巨懒,于是他
把这个回答的任务交给了你。




Input

 第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。
N≤1000000,Q≤3000,1≤W≤1000,1≤C≤1,000,000,000




Output

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

Sample Input

5 3
1 2 3 4 5
A 1 5 4
M 3 5 1
A 1 5 4

Sample Output

2
3
【输入输出样例说明】
原先5个英雄身高为1、2、3、4、5,此时[1, 5]间有2个英雄的身高大于等于4。
教主施法后变为1、2、4、5、6,此时[1, 5]间有3个英雄的身高大于等于4。
这不是我这个蒟蒻能够做出来的题,太难了,改了一个世纪
具体思路看这里https://www.cnblogs.com/wzx-RS-STHN/
 1 #include<bits/stdc++.h>
 2 #pragma GCC optimize("O3")
 3 #pragma GCC optimize("O2")
 4 using namespace std;
 5 typedef long long ll;
 6 ll belong[1000001],n,q,a[1000001],tag[1000001],block,b[1000001];
 7 ll L(ll i) {
 8     return (i-1)*block+1;
 9 }
10 ll R(ll i) {
11     return i*block;
12 }
13 ll rebuild(ll x) {
14     for(ll i=L(belong[x]); i<=R(belong[x]); i++)
15         b[i]=a[i];
16     sort(b+L(belong[x]),b+R(belong[x])+1);
17 }
18 void add(ll l,ll r,ll c) {
19     if(belong[l]==belong[r]) {
20         for(ll i=l; i<=r; i++)
21             a[i]+=c;
22         rebuild(l);
23     } else {
24         for(ll i=belong[l]+1; i<=belong[r]-1; i++)
25             tag[i]+=c;
26         for(ll i=l; i<=R(belong[l]); i++)
27             a[i]+=c;
28         rebuild(l);
29         for(ll i=L(belong[r]); i<=r; i++)
30             a[i]+=c;
31         rebuild(r);
32     }
33 }
34 ll find(ll l,ll r,ll c) {
35     ll ans=0;
36     if(belong[l]==belong[r]) {
37         for(ll i=l; i<=r; i++)
38             if(a[i]+tag[belong[i]]>=c)
39                 ans++;
40         return ans;
41     } else {
42         for(ll i=belong[l]+1; i<belong[r]; i++) {
43             ll l=L(i);
44             ll r=R(i);
45             ll tot=0,mid;
46             while(l<=r) {
47                 mid=(l+r)>>1;
48                 if(b[mid]+tag[i]>=c)
49                     r=mid-1,tot=R(i)-mid+1;
50                 else
51                     l=mid+1;
52             }
53             ans+=tot;
54         }
55         for(ll i=l; i<=R(belong[l]); i++)
56             if(a[i]+tag[belong[i]]>=c)
57                 ans++;
58         for(ll i=L(belong[r]); i<=r; i++)
59             if(a[i]+tag[belong[i]]>=c)
60                 ans++;
61         return ans;
62     }
63 }
64 int main() {
65     scanf("%lld%lld",&n,&q);
66     block=sqrt(n);
67     for(ll i=1; i<=n; i++) {
68         scanf("%lld",&a[i]);
69         belong[i]=(i-1)/block+1;
70         b[i]=a[i];
71     }
72     ll t=n/block;
73     if(n%block)
74         t++;
75     for(ll i=1; i<=t; i++)
76         sort(b+L(i),b+R(i)+1);
77     char otp;
78     ll l,r,c;
79     for(ll i=1; i<=q; i++) {
80         cin>>otp;
81         scanf("%lld %lld %lld",&l,&r,&c);
82         if(otp=='M')
83             add(l,r,c);
84         else
85             printf("%lld\n",find(l,r,c));
86     }
87     return 0;
88 }

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!