人傻常数大,萌新被卡爆了/ll
查看原帖
人傻常数大,萌新被卡爆了/ll
203008
山田リョウ楼主2023/10/17 21:26
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<ctype.h>
namespace fasti{
	char buf[1<<21],*p1=buf,*p2=buf;
	inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*(p1++);}
	inline void read(int&x){
        char c=getc(),f=0;
        for(;!isdigit(c);c=getc())f^=!(c^'-');
        for(x=0;isdigit(c);c=getc())x=x*10+(c^48);
        if(f)x=-x;--p1;
	}
	template<typename... Args>
	inline void read(int&x,Args&...args){read(x),read(args...);}
}
using fasti::getc;
using fasti::read;
const int bl=200;
int a[100001],b[100001],tag[100001],n;
bool cmp(const int&x,const int&y){return a[x]<a[y];}
void add(int t,int l,int r,int k){
    static std::queue<int>p,q;
    for(int i=(t-1)*bl+1;i<=t*bl&&t<=n;++i)
        if(l<=b[i]&&b[i]<=r)
            a[b[i]]+=k,p.push(b[i]);
        else
            q.push(b[i]);
    int s=(t-1)*bl+1;
    for(;p.size()&&q.size();)
        if(cmp(p.front(),q.front()))
            b[s++]=p.front(),p.pop();
        else
            b[s++]=q.front(),q.pop();
    for(;p.size();p.pop())b[s++]=p.front();
    for(;q.size();q.pop())b[s++]=q.front();
}
int min(int a,int b){return a<b?a:b;}
int max(int a,int b){return a>b?a:b;}
int getmin(int l,int r){
    if((l-1)/bl!=(r-1)/bl){
        int res=2147483647,L=((l+bl-2)/bl)*bl+1,R=(r/bl)*bl;
        for(int i=l;i<L;++i)res=min(res,a[i]+tag[(i+bl-1)/bl]);
        for(int i=R+1;i<=r;++i)res=min(res,a[i]+tag[(i+bl-1)/bl]);
        for(int i=L;i<=R;i+=bl)res=min(res,a[b[i]]+tag[i/bl+1]);
        return res;
    }else{
        int res=2147483647;
        for(int i=l;i<=r;++i)res=min(res,a[i]+tag[(i+bl-1)/bl]);
        return res;
    }
}
int getmax(int l,int r){
    if((l-1)/bl!=(r-1)/bl){
        int res=-2147483648,L=((l+bl-2)/bl)*bl+1,R=(r/bl)*bl;
        for(int i=l;i<L;++i)res=max(res,a[i]+tag[(i+bl-1)/bl]);
        for(int i=R+1;i<=r;++i)res=max(res,a[i]+tag[(i+bl-1)/bl]);
        for(int i=L;i<=R;i+=bl)res=max(res,a[b[min(i+bl-1,n)]]+tag[i/bl+1]);
        return res;
    }else{
        int res=-2147483648;
        for(int i=l;i<=r;++i)res=max(res,a[i]+tag[(i+bl-1)/bl]);
        return res;
    }
}
int rnk(int l,int r,int k){
    if((l-1)/bl!=(r-1)/bl){
        int res=0,L=((l+bl-2)/bl)*bl+1,R=(r/bl)*bl;
        for(int i=l;i<L;++i)if(a[i]+tag[(i+bl-1)/bl]<k)++res;
        for(int i=R+1;i<=r;++i)if(a[i]+tag[(i+bl-1)/bl]<k)++res;
        for(int i=L;i<=R;i+=bl)
            a[0]=k-tag[i/bl+1],res+=std::lower_bound(b+i,b+(i+bl-1>n?n:i+bl-1)+1,0,cmp)-b-i;
        return res;
    }else{
        int res=0;
        for(int i=l;i<=r;++i)if(a[i]+tag[(i+bl-1)/bl]<k)++res;
        return res;
    }
}
int main(){
    int m;
    read(n,m);
    for(int i=1;i<=n;++i)read(a[i]),b[i]=i;
    for(int i=1;(i-1)*bl<n;++i)std::sort(b+(i-1)*bl+1,b+(i*bl>n?n:i*bl)+1,cmp);
    for(int op,l,r,k;m--;){
        read(op,l,r,k);
        if(op==1){
            if(k<1||k>(r-l+1))puts("-1");
            else{
                --k;
                int L=getmin(l,r),R=getmax(l,r);
                for(;L<R;){
                    int mid=(1ll+L+R)>>1,t=rnk(l,r,mid);
                    if(t<=k)L=mid;
                    else R=mid-1;
                }
                printf("%d\n",L);
            }
        }else{
            if((l-1)/bl!=(r-1)/bl){
                int L=((l+bl-2)/bl)*bl+1,R=(r/bl)*bl;
                if(l<L)add(L/bl,l,L-1,k);
                if(R<r)add(R/bl+1,R+1,r,k);
                for(int i=L;i<=R;i+=bl)tag[i/bl+1]+=k;
            }else add((l-1)/bl+1,l,r,k);
        }
    }
    return 0;
}

目前测试发现当块长取 200200 时最优,而当块长取 300300 时会出现玄学 WA 和 RE

区间加和查询排名的代码通过了教主的魔法那题,所以应该是没问题的,但是看起来我的二分也没挂啊……

2023/10/17 21:26
加载中...