分块,吸氧90pts,TLE on #9求调qwq

P2801 教主的魔法

qwerasdasd1 @ 2022-12-15 00:06:16

rt

解释一下几个数组:st_i 是第 i 个块的起点,ed_i 则是终点,a_i 是原数组,id_i 是第 i 个数所在块的编号,delta_i 是第 i 个块的延迟标记,t_i 是用来排序的数组。

预言一波感觉又是犯了很nt的错误

#include<stdio.h>
#include<algorithm>
#include<math.h>
using namespace std;
const int N=1e6+5;
int n,q,num;
int st[N],ed[N],a[N],id[N],delta[N],t[N],size[N];
inline void write(int x);
inline int read();
void init();
void add(int l,int r,int c);
int query(int l,int r,int c);
int main(){
    n=read(),q=read();
    getchar();
    for(int i=1;i<=n;i++) a[i]=read();
    getchar();
    while(q--){
        char ch=getchar();
        int L=read(),R=read(),X=read(); 
        if(ch=='M'){
            add(L,R,X);
        }else if(ch=='A'){
            int ans=query(L,R,X);
            write(ans); 
            printf("\n");
        }
        if(q) getchar();
    }
    return 0;
}
inline int read(){
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*f;
}
inline void write(int x){if(x<0)x=~x+1,putchar('-');if(x>9)write(x/10);putchar(x%10+'0');}
void init(){
    num=sqrt(n); 
    for(int i=1;i<=num;i++) st[i]=n/num*(i-1)+1,ed[i]=n/num*i;
    ed[num]=n;
    for(int i=1;i<=num;i++){
        for(int j=st[i];j<=ed[i];j++) id[j]=i;
        size[i]=ed[i]-st[i]+1;
    } 
}
void Sort(int x){
    for(int i=st[x];i<=ed[x];i++) t[i]=a[i];
    sort(t+st[x],t+ed[x]+1);
}
void add(int l,int r,int c){
    int sid=id[l],eid=id[r];
    if(sid==eid){
        for(int i=l;i<=r;i++) a[i]+=c;
        Sort(sid);
        return ;
    }
    for(int i=l;i<=ed[sid];i++) a[i]+=c;
    for(int i=sid+1;i<eid;i++) delta[i]+=c;
    for(int i=st[eid];i<=r;i++) a[i]+=c;
    Sort(sid);
    Sort(eid);
    return ;
}
int query(int l,int r,int c){
    int sid=id[l],eid=id[r],ans=0;
    if(sid==eid){
        for(int i=l;i<=r;i++) ans+=(a[i]+delta[sid]>=c?1:0);
        return ans;
    }
    for(int i=l;i<=ed[sid];i++) ans+=(a[i]+delta[sid]>=c?1:0);
    for(int i=sid+1;i<eid;i++) ans+=(ed[i]-(lower_bound(t+st[i],t+ed[i]+1,c-delta[i])-t)+1);
    for(int i=st[eid];i<=r;i++) ans+=(a[i]+delta[eid]>=c?1:0);
    return ans;
}

by _maojun__ @ 2022-12-15 07:28:25

@Twinkling_S 但如果要卡常的话提醒一下,声明变量的过程挺慢的


by qwerasdasd1 @ 2022-12-15 07:52:57

@_maojun__ 我改了交了一发,还是T了qwq


by _maojun__ @ 2022-12-15 10:04:04

@Twinkling_S az 是不是一开始 init 的时候没有维护好 t


by AirQwQ @ 2022-12-15 11:06:16

卡下常数把,开O2本地1.5s,差得不多


by AirQwQ @ 2022-12-15 11:10:12

加个特判也能过((((

if(n==1000000&&q==3000&&a[1]==88&&a[2]==737){
        cout<<178725<<'\n';
        for(int i=1;i<=1517;i++)
            cout<<1000000<<'\n';
            return 0;
    }

by qwerasdasd1 @ 2022-12-15 11:55:18

@_maojun__ @Air_zyc 我知道了,问题有以下两点:

  1. main函数里没有init(),这个问题很奇怪,导致了#9 TLE 而其他能 AC,合理怀疑数据水了;

  2. init()里应当事先对 t_i 进行排序,我的 code 忘排了。这样可能导致修改+查询整块时 lower_bound() 失效。

  3. 样例的输入是有大问题的。如果用 getchar() 输入操作类型的话是一定会错的(因为题目数据点行间是无空格的)。因此应该用 scanf 输入输出。

最后,这道题已 A 。谢谢两位 dalao!!!


|