_Violet_ @ 2018-03-28 00:19:10
题解AC:
//因为看的这个题解,但是TLE了
//所以我交下试试,by Jianuo_Zhu
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<queue>
#include<cmath>
using namespace std;
const int maxn=1e6+10;
int n,q,a[maxn],b[maxn],l[maxn],r[maxn],belong[maxn],add[maxn],block,num;
void reset(int x){
for(int i=l[belong[x]]; i<=r[belong[x]]; i++) b[i] = a[i];
sort(b+l[belong[x]],b+r[belong[x]]+1);
}
void build(void){
block=sqrt(n);
num=n/block;if(n%block) num++;
for(int i=1;i<=n;i++)
belong[i]=(i-1)/block+1,b[i]=a[i];
for(int i=1;i<=num;i++)
l[i]=(i-1)*block+1,r[i]=i*block;
r[num]=n;
for(int i=1;i<=num;i++)
sort(b+l[i],b+r[i]+1);
return;
}
void update(int ll,int rr,int w){
if(belong[ll]==belong[rr]){
for(int i=ll;i<=rr;i++)
a[i]+=w;
reset(ll);return;
}
for(int i=ll;i<=r[belong[ll]];i++){
a[i]+=w;
}
for(int i=l[belong[rr]];i<=rr;i++){
a[i]+=w;
}
reset(ll);reset(rr);
for(int i=belong[ll]+1;i<belong[rr];i++)
add[i]+=w;
}
int find(int x,int w){
int ll=l[x],rr=r[x],mid;
while(ll<=rr){
mid=(ll+rr)/2;
if(b[mid]<w) ll=mid+1;
else rr=mid-1;
}
return r[x]-ll+1;
}
int ask(int ll,int rr,int w){
int cnt=0;
if(belong[ll]==belong[rr]){
for(int i=ll;i<=rr;i++)
if(a[i] + add[belong[ll]]>=w)cnt++;
return cnt;
}
for(int i=ll;i<=r[belong[ll]];i++)
if(a[i] + add[belong[i]]>=w) cnt++;
for(int i=l[belong[rr]];i<=rr;i++)
if(a[i] + add[belong[i]]>=w) cnt++;
for(int i=belong[ll]+1;i<belong[rr];i++)
cnt+=find(i,w-add[i]);
return cnt;
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build();
int x,y,w;
for(int i=1;i<=q;i++){
char c[5];
scanf("%s%d%d%d",c,&x,&y,&w);
if(c[0]=='M') update(x,y,w);
else printf("%d\n",ask(x,y,w));
}
return 0;
}
TLE(80分):
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define Re register
const int N = 1e6+7;
int n,Q;int a[N],b[N];
int blo[N],l[N],r[N];
inline void read(int &_){
_=0;char c=getchar();while(c>'9' || c<'0')c=getchar();
while(c>='0'&&c<='9'){_=(_<<3)+(_<<1)+(c^48);c=getchar();}
}
inline void build(){
Re int sz=sqrt(n);
Re int tot = n/sz;
if(n%sz) tot++;
for(Re int i=1;i<=tot;++i)
l[i]=(i-1)*sz+1,r[i]=i*sz;
r[tot] = n;
for(Re int i=1;i<=n;++i)
blo[i]=(i-1)/sz+1,b[i]=a[i];
for(Re int i=1;i<=tot;++i)
sort(b+l[i],b+r[i]+1);
}
inline void init(int L){
for(Re int i=l[blo[L]];i<=r[blo[L]];++i)
b[i]=a[i];
sort(b+l[blo[L]],b+r[blo[L]]+1);
}
int add[N];
inline void update(int L,int R,int k){
if(blo[L]==blo[R]){
for(Re int i=L;i<=R;++i)
a[i]+=k;
init(L);return;
}
for(Re int i=L;i<=r[blo[L]];++i)
a[i]+=k;
for(Re int i=l[blo[R]];i<=R;++i)
a[i]+=k;
init(L);init(R);
for(Re int i=blo[L]+1;i<blo[R];++i)
add[i]+=k;
}
inline int search(int now,int k){
Re int L=l[now],R=r[now];
while(L<R){
Re int mid=L+R>>1;
if(b[mid]<k)L=mid+1;
else R=mid;
}
return r[now]-R+1;
}
inline int ask(int L,int R,int k){
Re int cnt=0;
if(blo[L]==blo[R]){
for(Re int i=L;i<=R;++i)
if(a[i]+add[i]>=k)
++cnt;
return cnt;
}
for(Re int i=L;i<=r[blo[L]];++i)
if(a[i]+add[i]>=k)
++cnt;
for(Re int i=l[blo[R]];i<=R;++i)
if(a[i]+add[i]>=k)
++cnt;
for(Re int i=blo[L]+1;i<blo[R];++i)
cnt+=search(i,k-add[i]);
return cnt;
}
int main(){
read(n);
read(Q);
for(Re int i=1;i<=n;++i)
read(a[i]);
Re int x,y,k;
for(Re int i=0;i<Q;++i){
char c[5];scanf("%s",c);
read(x);read(y);read(k);
if(c[0]=='M') update(x,y,k);
else printf("%d",ask(x,y,k)),putchar(10);
}
return 0;
}
by SofanHe @ 2018-03-28 07:21:12
if(a[i]+add[i]>=k)
add是对块的,这样是不行的.
下面几个add同理.
@Rexy 话说您这就学分块?
by _Violet_ @ 2018-03-28 23:44:54
@多功能的荀彧 谢谢dalao,
话说我这种错误不只一次了
话说学分块,没毛病
by _Violet_ @ 2018-03-28 23:49:30
@多功能的荀彧 然而还是TLE(90分)
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define Re register
const int N = 1e6+7;
int n,Q;int a[N],b[N];
int blo[N],l[N],r[N];
inline void read(int &_){
_=0;char c=getchar();while(c>'9' || c<'0')c=getchar();
while(c>='0'&&c<='9'){_=(_<<3)+(_<<1)+(c^48);c=getchar();}
}
inline void build(){
Re int sz=sqrt(n);
Re int tot= n/sz ;
if(n%sz) tot++;
for(Re int i=1;i<=tot;++i)
l[i]=(i-1)*sz+1,r[i]=i*sz;
r[tot] = n;
for(Re int i=1;i<=n;++i)
blo[i]=(i-1)/sz+1,b[i]=a[i];
for(Re int i=1;i<=tot;++i)
sort(b+l[i],b+r[i]+1);
}
inline void init(int L){
for(Re int i=l[blo[L]];i<=r[blo[L]];++i)
b[i]=a[i];
sort(b+l[blo[L]],b+r[blo[L]]+1);
}
int add[N];
inline void update(int L,int R,int k){
if(blo[L]==blo[R]){
for(Re int i=L;i<=R;++i)
a[i]+=k;
init(L);return;
}
for(Re int i=L;i<=r[blo[L]];++i)
a[i]+=k;
for(Re int i=l[blo[R]];i<=R;++i)
a[i]+=k;
init(L);init(R);
for(Re int i=blo[L]+1;i<blo[R];++i)
add[i]+=k;
}
inline int search(int now,int k){
Re int L=l[now],R=r[now];
while(L<R){
Re int mid=L+R>>1;
if(b[mid]<k)L=mid+1;
else R=mid;
}
return r[now]-R+1;
}
inline int ask(int L,int R,int k){
Re int cnt=0;
if(blo[L]==blo[R]){
for(Re int i=L;i<=R;++i)
if(a[i]+add[blo[i]]>=k)
++cnt;
return cnt;
}
for(Re int i=L;i<=r[blo[L]];++i)
if(a[i]+add[blo[i]]>=k)
++cnt;
for(Re int i=l[blo[R]];i<=R;++i)
if(a[i]+add[blo[i]]>=k)
++cnt;
for(Re int i=blo[L]+1;i<blo[R];++i)
cnt+=search(i,k-add[i]);
return cnt;
}
int main(){
read(n);
read(Q);
for(Re int i=1;i<=n;++i)
read(a[i]);
Re int x,y,k;
for(Re int i=0;i<Q;++i){
char c[5];scanf("%s",c);
read(x);read(y);read(k);
if(c[0]=='M') update(x,y,k);
else printf("%d",ask(x,y,k)),putchar(10);
}
return 0;
}
by _Violet_ @ 2018-03-29 00:03:30
@多功能的荀彧 dalao,我发现我TLE的原因是读入
然而改后第一个点Wa掉了,然后改了一下二分就过了
您介意给我讲下标程的二分原理吗
by SofanHe @ 2018-03-29 06:29:56
@Rexy
二分就是找一个位置让它右面的全都是
因为
因此我们就能得到这样的二分式子啊