#分块,二分#洛谷 5356 [Ynoi2017] 由乃打扑克

题目

支持区间加和区间查询第 \(k\)


分析

分块之后给每个整块排序,这样修改的时候整块打标记,散块直接分开把需要加的部分暴力加之后归并,就是 \(O(\sqrt{n})\)

查询的话,如果只有散块直接归并出结果,否则二分答案,加上小块合并成的整块,相当于是整体二分,就是 \(O(\sqrt{n}\log{a_i})\)

理论上块长取 \(\sqrt{n}\log{n}\) 实际上直接取根号更快


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=100011;
int n,Q,a[N],lazy[N],b[N],rk[N],rK[N],Rk[N],L[N],R[N],pos[N],bl,_l[N],_r[N],_mid[N];
int iut(){
    int ans=0,f=1; char c=getchar();
    while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
    while (isdigit(c)) ans=ans*10+c-48,c=getchar();
    return ans*f;
}
void print(int ans){
    if (ans<0) putchar('-'),ans=-ans;
    if (ans>9) print(ans/10);
    putchar(ans%10+48);
}
bool cmp(int x,int y){return a[x]<a[y];}
void rebuild(int x,int l,int r,int z){
    Rk[0]=rK[0]=0;
    for (int i=L[x];i<=R[x];++i)
    if (l<=rk[i]&&rk[i]<=r) Rk[++Rk[0]]=rk[i],a[rk[i]]+=z;
        else rK[++rK[0]]=rk[i];
    int i1=1,j1=1,j=L[x];
    while (i1<=Rk[0]&&j1<=rK[0])
        if (a[Rk[i1]]<a[rK[j1]]) rk[j++]=Rk[i1++];
            else rk[j++]=rK[j1++];
    while (i1<=Rk[0]) rk[j++]=Rk[i1++];
    while (j1<=rK[0]) rk[j++]=rK[j1++];
}
int main(){
    n=iut(),Q=iut(),bl=sqrt(n);
    for (int i=1;i<=n;++i) a[i]=iut(),pos[i]=(i-1)/bl+1,rk[i]=i;
    for (int i=1;i<=n;++i) if (!L[pos[i]]) L[pos[i]]=i;
    for (int i=n;i>=1;--i) if (!R[pos[i]]) R[pos[i]]=i;
    for (int i=1;i<=pos[n];++i) sort(rk+L[i],rk+R[i]+1,cmp);
    for (int i=1;i<=Q;++i){
        int opt=iut(),l=iut(),r=iut(),z=iut();
        if (opt==1){
            if (r-l+1<z||z<=0){
                print(-1),putchar(10);
                continue;
            }
            int ans=-1;
            if (pos[l]==pos[r]){
                for (int j=L[pos[l]];j<=R[pos[r]]&&z;++j)
                    if (l<=rk[j]&&rk[j]<=r) ans=a[rk[j]]+lazy[pos[l]],--z;
                print(ans),putchar(10);
            }else{
                Rk[0]=rK[0]=0;
                for (int j=L[pos[l]];j<=R[pos[l]];++j)
                    if (rk[j]>=l) Rk[++Rk[0]]=a[rk[j]]+lazy[pos[l]];
                for (int j=L[pos[r]];j<=R[pos[r]];++j)
                    if (rk[j]<=r) rK[++rK[0]]=a[rk[j]]+lazy[pos[r]];
                int i1=1,j1=1,len=0;
                while (i1<=Rk[0]&&j1<=rK[0])
                if (Rk[i1]<rK[j1]) b[++len]=Rk[i1++];
                    else b[++len]=rK[j1++];
                while (i1<=Rk[0]) b[++len]=Rk[i1++];
                while (j1<=rK[0]) b[++len]=rK[j1++];
                if (pos[l]+1==pos[r]) print(b[z]),putchar(10);
                else{
                    int mn=b[1],mx=b[len],cnt=0;
                    for (int j=pos[l]+1;j<pos[r];++j){
                        mn=min(mn,a[rk[L[j]]]+lazy[j]);
                        mx=max(mx,a[rk[R[j]]]+lazy[j]);
                        _l[j]=L[j],_r[j]=R[j];
                    }
                    _l[0]=1,_r[0]=len;
                    while (mn<mx){
                        int mid=(0ll+mn+mx)>>1,_L,_R,CNT=cnt;
                        if (_l[0]<=_r[0]){
                            _L=_l[0]-1,_R=_r[0];
                            while (_L<_R){
                                int _MID=(_L+_R+1)>>1;
                                if (b[_MID]<=mid) _L=_MID;
                                    else _R=_MID-1;
                            }
                            _mid[0]=_L,cnt+=_L-_l[0]+1;
                        }
                        for (int j=pos[l]+1;j<pos[r];++j)
                        if (_l[j]<=_r[j]){
                            _L=_l[j]-1,_R=_r[j];
                            while (_L<_R){
                                int _MID=(_L+_R+1)>>1;
                                if (a[rk[_MID]]+lazy[j]<=mid) _L=_MID;
                                    else _R=_MID-1;
                            }
                            _mid[j]=_L,cnt+=_L-_l[j]+1;
                        }
                        if (cnt<z){
                            mn=mid+1;
                            if (_l[0]<=_r[0]) _l[0]=_mid[0]+1;
                            for (int j=pos[l]+1;j<pos[r];++j)
                                if (_l[j]<=_r[j]) _l[j]=_mid[j]+1;
                        }else{
                            mx=mid;
                            if (_l[0]<=_r[0]) _r[0]=_mid[0];
                            for (int j=pos[l]+1;j<pos[r];++j)
                                if (_l[j]<=_r[j]) _r[j]=_mid[j];
                            cnt=CNT;
                        }
                    }
                    print(mn),putchar(10);
                }
            }
        }else{
            if (pos[l]==pos[r]){
                if (L[pos[l]]==l&&R[pos[r]]==r) lazy[pos[l]]+=z;
                    else rebuild(pos[l],l,r,z);
            }
            else{
                if (l==L[pos[l]]) lazy[pos[l]]+=z;
                    else rebuild(pos[l],l,R[pos[l]],z);
                if (r==R[pos[r]]) lazy[pos[r]]+=z;
                    else rebuild(pos[r],L[pos[r]],r,z);
                for (int j=pos[l]+1;j<pos[r];++j) lazy[j]+=z;
            }
        }
    }
    return 0;
}
posted @ 2024-02-26 16:09  lemondinosaur  阅读(6)  评论(0编辑  收藏  举报