本文主要是介绍bzoj3343 教主的魔法(权限题),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
bzoj传送门(权限)
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。
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
HINT
【输入输出样例说明】
原先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。
Source
题解
人生中的第一道分块题,感觉好无语啊。速度还是太慢了,开了O2才过
CODE:
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e6+10;
struct Block
{int l,r,num,plus;int a[1010];inline void keep(){sort(a+1,a+num+1);}inline int find(int n){int L=1,R=num,mid;n-=plus;while(L<R){mid=(L+R)>>1;if(a[mid]<n) L=mid+1;else R=mid;}return L;}
}a[1010];
int s[N];
int belong[N];
int n,q,x,y,z,ans,block,num;
char c;
inline void read(int &n)
{n=0;char c=getchar();while(c<'0'||c>'9') c=getchar();while(c>='0'&&c<='9') n=n*10+c-48,c=getchar();
}
inline void build()
{block=sqrt(n);num=n/block;if(n%block) num++;for(int i=1;i<=num;i++)a[i].l=(i-1)*block+1,a[i].r=i*block,a[i].num=block;a[num].r=n;a[num].num=a[num].r-a[num].l+1;for(int i=1;i<=n;i++)belong[i]=(i-1)/block+1;for(int i=1;i<=num;i++){for(int j=a[i].l;j<=a[i].r;j++)a[i].a[j-a[i].l+1]=s[j];a[i].keep();}
}
inline void add(int x,int y,int z)
{if(belong[x]==belong[y]){for(int i=x;i<=y;i++)s[i]+=z;for(int i=a[belong[x]].l;i<=a[belong[x]].r;i++)a[belong[x]].a[i-a[belong[x]].l+1]=s[i];a[belong[x]].keep();return;}for(int i=x;i<=a[belong[x]].r;i++)s[i]+=z;for(int i=a[belong[x]].l;i<=a[belong[x]].r;i++)a[belong[x]].a[i-a[belong[x]].l+1]=s[i];a[belong[x]].keep();for(int i=belong[x]+1;i<belong[y];i++)a[i].plus+=z;for(int i=a[belong[y]].l;i<=y;i++)s[i]+=z;for(int i=a[belong[y]].l;i<=a[belong[y]].r;i++)a[belong[y]].a[i-a[belong[y]].l+1]=s[i];a[belong[y]].keep();
}
inline int ask(int x,int y,int z)
{int ans=0;if(belong[x]==belong[y]){for(int i=x;i<=y;i++)if(s[i]+a[belong[x]].plus>=z) ans++;return ans;}for(int i=x;i<=a[belong[x]].r;i++)if(s[i]+a[belong[x]].plus>=z) ans++;for(int i=belong[x]+1;i<belong[y];i++){int p=a[i].find(z);if(a[i].a[p]+a[i].plus>=z) ans+=a[i].num-p+1;}for(int i=a[belong[y]].l;i<=y;i++)if(s[i]+a[belong[y]].plus>=z) ans++;return ans;
}
int main()
{read(n),read(q);for(int i=1;i<=n;i++)read(s[i]);build();while(q--){c=getchar();while(c!='A'&&c!='M') c=getchar();read(x),read(y),read(z);if(c=='A') printf("%d\n",ask(x,y,z));else add(x,y,z);}return 0;
}
这篇关于bzoj3343 教主的魔法(权限题)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!