洛谷 P2801 教主的魔法 题解
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 P2801 教主的魔法 题解相关的知识,希望对你有一定的参考价值。
此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置。
题目链接:https://www.luogu.org/problem/show?pid=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的英雄数。
输入输出样例
5 3 1 2 3 4 5 A 1 5 4 M 3 5 1 A 1 5 4
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。
分析:
题目看起来很简单,但是一百万的数据量,暴力写的话绝对超时。
TLE怎么办?区间修改询问用分块~
AC代码:.(感谢@WZY大佬提供题解程序供博主学习...)
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 inline void read(int &x) 6 {//快速读入 7 char ch = getchar();char c;x = 0; 8 while(ch >‘9‘ || ch < ‘0‘) c = ch,ch = getchar(); 9 while(ch >= ‘0‘ && ch <= ‘9‘) x = x*10 +ch-‘0‘,ch = getchar(); 10 if(c == ‘-‘) x = -x; 11 } 12 inline void put(int x) 13 {//快速输出 14 if (x < 0)x = ~x + 1, putchar(‘-‘); 15 if (x > 9) put(x / 10);putchar(x % 10 + 48); 16 } 17 const int MAXN = 1000008; 18 const int SN = 1008; 19 int num[MAXN],s[MAXN],belong[MAXN],flag[MAXN],block,size; 20 // 原始··· 块内·· 归属···· 加法标记·· 块数 ·每块的大小 21 int L[MAXN],R[MAXN]; 22 //L[i]:块i的左端点下标 R[i]:块i的右端点下标 23 24 int res(int x) 25 {//对第x个块进行排序 26 int l = L[x],r = R[x]; 27 for(register int i = l;i <= r;i ++) 28 s[i] = num[i]; 29 std::sort(s+l,s+r+1); 30 } 31 32 int find(int x,int k) 33 {//二分查找第x个块,并找出大于k的部分 34 int l = L[x],r = R[x]; 35 int last = r; 36 int mid; 37 while(l <= r) 38 { 39 mid = (l + r) >> 1; 40 if(s[mid] < k) l = mid + 1; 41 else r = mid - 1; 42 } 43 return last - l + 1; 44 } 45 46 inline void modify(int l,int r,int k) 47 {//区间修改 48 if(belong[l] == belong[r]) 49 { 50 for(register int i = l;i <= r;i ++) 51 num[i] = num[i] + k; 52 res(belong[l]); 53 return; 54 } 55 56 register int ll = belong[l],rr = belong[r]; 57 if(L[ll] < l) 58 { 59 for(register int i = l;i <= R[ll];i ++) 60 num[i] += k; 61 res(belong[l]); 62 ++ ll; 63 } 64 if(R[rr] > r) 65 { 66 for(register int i = L[rr];i <= r;i ++) 67 num[i] += k; 68 res(belong[r]); 69 -- rr; 70 } 71 for(register int i = ll;i <= rr;++ i) 72 flag[i] += k; 73 } 74 75 int ask(int l,int r,int k) 76 {//区间询问 77 register int ans = 0; 78 if(belong[l] == belong[r]) 79 { 80 for(int i = l;i <=r;++ i) 81 if(num[i] + flag[belong[i]] >= k) 82 ans ++; 83 return ans; 84 } 85 register int ll = belong[l],rr = belong[r]; 86 if(L[ll] < l) 87 { 88 for(register int i = ll;i <= R[ll];i ++) 89 if(num[i] + flag[belong[i]] >= k) 90 ans ++; 91 ++ ll; 92 } 93 if(R[rr] > r) 94 { 95 for(register int i = L[rr];i <= r;++ i) 96 if(num[i] + flag[belong[i]] >= k) 97 ans ++; 98 -- rr; 99 } 100 for(register int i = ll;i <= rr;++ i) 101 ans = ans + find(i,k - flag[i]); 102 return ans; 103 } 104 int main() 105 { 106 int n,q; 107 read(n),read(q); 108 register char c; 109 register int l,r,x; 110 /*------------------------------------------------*/ 111 //初始化各个块 112 block = sqrt(n); 113 if(n % block) size = n/block + 1; 114 else size = n/block; 115 116 for(register int i = 1;i <= n;++ i) 117 { 118 read(num[i]); 119 belong[i] = (i - 1)/block + 1; 120 s[i] = num[i]; 121 } 122 for(register int i = 1;i <= size;++ i) 123 { 124 L[i] = (i -1) * block + 1; 125 R[i] = i * block; 126 } 127 if(R[size] > n) R[size] = n; 128 for(register int i = 1;i <= size;++ i) 129 res(i); 130 /*------------------------------------------------*/ 131 //处理修改和询问操作 132 for(register int i = 1;i <= q; ++ i) 133 { 134 c = getchar(); 135 while(c < 30) c = getchar(); 136 read(l),read(r),read(x); 137 if(c == ‘A‘) 138 put(ask(l,r,x)),putchar(‘\\n‘); 139 else 140 modify(l,r,x); 141 } 142 return 0; 143 }
洛谷这道题的数据比较弱,所以容易AC
以上是关于洛谷 P2801 教主的魔法 题解的主要内容,如果未能解决你的问题,请参考以下文章