由乃打扑克

题目链接 : 由乃打扑克

既然是Ynoi的题,先考虑分块

看到诡异的操作,\(n\le 10^5\),考虑分块。

区间加非常好做。

至于区间\(rank\),发现一句重要的话\(-2\times 10^4\le 每次加上的数和原序列的数\le 2\times 10^4\),而考虑极限情况下也就是\(2\times 10^4\times 10001=2000020000\),而且\(log(2000020000)<31\),所以可以考虑二分答案。

然后这道题就做完了——吗?

显然Ynoi不可能这么简单。

需要考虑一些优化才可以过掉这道题。

  1. 将散块单独拿出来,组成一个新的块。这样可以优化掉一部分

  2. 对于整块的最大值小于二分出的答案,直接加上整块长度

  3. 对于整块的最小值大于二分出的答案的,直接跳过

加上这几个优化就可以不加卡常轻松过掉这道题了

tips : 二分答案时所使用的left和right虽然没有超过int,但left+right超过了int范围,所以要开long long

点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
#ifdef LOCAL
    FILE *InFile = infile("in.in"),*OutFile = outfile("out.out");
    // FILE *ErrFile=errfile("err.err");
#else
    FILE *Infile = stdin,*OutFile = stdout;
    //FILE *ErrFile = stderr;
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
namespace IO{
    char buf[1<<20],*p1,*p2;
#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define pc putchar_unlocked
    template<class T>
    inline void read(T &x){
        x = 0;bool f = false;char s = gc();
        for(;s < '0'||'9' < s;s = gc()) f |= (s == '-');
        for(;'0' <= s && s <= '9';s = gc())
            x = (x<<1) + (x<<3) + (s^48);
        x = f?-x:x;
    }
    template<class T,class ...Args>
    inline void read(T &x,Args&... args){read(x);read(args...);}
    template<class T>
    inline void write(T x){
        static char Out[30];static int top;top = 0;
        if(x < 0) x = -x,pc('-');
        do{Out[++top] = x%10+'0';}while(x/=10);
        while(top) pc(Out[top--]);
    }
    inline void write(char x){pc(x);}
    template<class T,class ...Args>
    inline void write(T x,Args... args){write(x);write(args...);}
}using namespace IO;
const int N = 1e5 + 10,M = 350;
vector<int> num[M];
int n,m,pos[N],L[M],R[M],len,a[N],add[M];
inline void solve(){
    read(n,m);
    for(int i = 1;i <= n; ++i) read(a[i]);

    len = sqrt(n);
    for(int i = 1;i <= len; ++i) L[i] = R[i - 1] + 1,R[i] = i * len;
    if(R[len] < n) len++,L[len] = R[len - 1] + 1,R[len] = n;
    for(int i = 1;i <= len; ++i){
        for(int j = L[i];j <= R[i]; ++j){
            pos[j] = i;
            num[i].emplace_back(a[j]);
        }
        sort(num[i].begin(),num[i].end());
    }
    
    auto rebuild = [&](int pos) -> void{
        vector<int> res;
        for(int i = L[pos];i <= R[pos]; ++i) res.emplace_back(a[i]);
        sort(res.begin(),res.end());
        num[pos] = res;
    };

    auto change = [&](int l,int r,int k) -> void{
        int p = pos[l],q = pos[r];
        if(p == q){
            for(int i = l;i <= r; ++i) a[i] += k;
            rebuild(p);
            return;
        }
        for(int i = l;i <= R[p]; ++i) a[i] += k;
        rebuild(p);
        for(int i = L[q];i <= r; ++i) a[i] += k;
        rebuild(q);
        for(int i = p + 1;i < q; ++i) add[i] += k;
    };

    auto get = [&](int l,int r) -> pair<int,int>{
        int p = pos[l],q = pos[r],mn = 0x3f3f3f3f,mx = -0x3f3f3f3f;
        if(r < l) return make_pair(mn,mx);
        if(p == q){
            for(int i = l;i <= r; ++i) 
                mn = min(mn,a[i] + add[p]),
                mx = max(mx,a[i] + add[p]);
            return make_pair(mn,mx);
        }
        for(int i = l;i <= R[p]; ++i)
            mn = min(mn,a[i] + add[p]),
            mx = max(mx,a[i] + add[p]);
        for(int i = L[q];i <= r; ++i)
	        mn = min(mn,a[i] + add[q]),
            mx = max(mx,a[i] + add[q]);
        for(int i = p + 1;i < q; ++i)
            mn = min(mn,num[i].front() + add[i]),
            mx = max(mx,num[i].back() + add[i]);
        return make_pair(mn,mx);
    };

    auto check = [&](int l,int r,int k) -> int{
        if(l > r) return 0;
        int p = pos[l],q = pos[r],res = 0;
        for(int i = p;i <= q; ++i){
            if(num[i].front() + add[i] > k) continue;
            else if(num[i].back() + add[i] <= k) res += num[i].size();
            else{
                res += upper_bound(num[i].begin(),num[i].end(),k-add[i]) - num[i].begin();
            }
        }
        return res;
    };

    auto query = [&](int l,int r,int k) -> int{
        int resl = l,resr = r;
        if(r - l + 1 < k) return -1;
        vector<int> san;
        int p = pos[l],q = pos[r],ans = 0;
        if(p != q){
            for(int i = l;i <= R[p]; ++i) san.emplace_back(a[i] + add[p]);
            for(int i = L[q];i <= r; ++i) san.emplace_back(a[i] + add[q]);
        }
        else{
            for(int i = l;i <= r; ++i) san.emplace_back(a[i]+add[p]);
        }
        sort(san.begin(),san.end());
        
        l = R[p] + 1,r = L[q] - 1;
        pair<int,int> res = get(l,r);
        int left = res.first,right = res.second;
        
        if(san.size()) left = min(left,san.front()),right = max(right,san.back());
        if(k == resr - resl + 1) return right;
        if(k == 1) return left;
        while(left <= right){
            int mid = (0ll + left + right) >> 1;
            int more = upper_bound(san.begin(),san.end(),mid) - san.begin();
            if(check(l,r,mid) + more >= k) ans = mid,right = mid - 1;
            else left = mid + 1;
        }
        return ans;
    };
    for(int i = 1,op,l,r,k;i <= m; ++i){
        read(op,l,r,k);
        if(op == 1) write(query(l,r,k),'\n');
        else change(l,r,k);
    }
}
signed main(){
    //cin.tie(nullptr)->sync_with_stdio(false);
    //cout.tie(nullptr)->sync_with_stdio(false);
    solve();
}

upd:附加一个多年前的代码,目前在luogu最优解第3页,当时狂T不止,死因是left+right没开long long

点此查看代码
#include<bits/stdc++.h>
#include<sys/mman.h>
#include<fcntl.h>
using namespace std;
using llt=long long;
using llf=long double;
using ull=unsigned long long;
#define Ct const
#define For(i,a,b,c) for(int i=(a);i<=(b);i+=(c))
#define For_(i,a,b,c) for(int i=(a);i>=(b);i-=(c))
#define For_it(i,a,b) for(auto i=(a);i!=(b);++i)
namespace IO{
#ifdef ONLINE_JUDGE
	int Fin=fileno(stdin);
	FILE* Fout(stdout);
#else
	int Fin=open("in.in",0);
	FILE* Fout(fopen("out.out","w"));
#endif
	Ct char *I=(char*)mmap(0,1<<30,1,2,Fin,0);
	template<class T> void read(T &x){
		x=0; bool f=0; while(!isdigit(*I)){if(*I=='-') f=1; ++I;}
		while(isdigit(*I)) x=x*10+(*I++&15); if(f) x=-x;
	}
	void read(string& s){s.clear(); while(*I<33) ++I; while(*I>32) s.push_back(*I++);}
	void read(char* s){int pos=0; while(*I<33) ++I; while(*I>32) s[pos++]=*I++;}
	template<class T=int> T read(){T a; read(a); return a;}
	template<class T,class... Argc> void read(T &x,Argc&... argc){read(x),read(argc...);}
    class qostream{
        static constexpr size_t SIZE=1<<20,BLOCK=64,FLSIZE=64; FILE *fp; char buf[SIZE]; int p;
        char flbuf[FLSIZE]; int prec; unsigned long long flen;
        void flush(){if(p+BLOCK>=SIZE) fwrite(buf,1,p,fp),p=0;} void putch(const char& ch){flush();buf[p++]=ch;}
    public:
        void Set_Persicion(const size_t& x){prec=x;flen=(unsigned long long)(pow(10,x));}
        qostream(FILE *_fp=stdout,const size_t& p=6):fp(_fp),p(0){Set_Persicion(p);} ~qostream(){fwrite(buf, 1, p, fp);}
        template<class T>
        typename enable_if<is_integral<T>::value|is_same<T,__int128_t>::value,qostream>::type &operator<<(T x){
            int len=0; flush(); x<0?(x=-x,buf[p++]='-'):0; do buf[p+len]=x%10+'0',x/=10,++len; while(x);
            for(int i=0,j=len-1;i<j;++i,--j) swap(buf[p+i],buf[p+j]); p+=len; return*this;
        } template<class T> typename enable_if<is_floating_point<T>::value,qostream>::type &operator<<(T x){
            int len=0; flush(); x<0?(x=-x,buf[p++]='-'):0; x*=flen; unsigned long long ret=x;
            if(x-ret>=0.4999999999) ++ret; if(ret) do flbuf[len++]=ret%10+'0',ret/=10; while(ret);
            if(len>prec){do buf[p++]=flbuf[--len]; while(len>prec); buf[p++]='.';} else{buf[p++]='0',buf[p++]='.';
            for(size_t i=prec-len;i--;) buf[p++]='0';} do buf[p++]=flbuf[--len]; while(len); return*this;
        }
        qostream &operator<<(const char& x){putch(x); return*this;}
        qostream &operator<<(const char *str){while(*str) putch(*str++); return*this;}
        qostream &operator<<(const string& str){return *this<<str.c_str();}
    }cout(Fout);
}using IO::read;
#define cout IO::cout
const int N=1e5+10,M=sqrt(N)+10;
int n,m,a[N],add[M],L[M],R[M],pos[N],len;
vector<pair<int,int> > num[M];
#define pii pair<int,int>
#define mk make_pair
inline void rebuild(int l,int r,int id,int p){
    vector<pii> res1,res2;
    for(auto k:num[id]){
        if(l<=k.second&&k.second<=r) res2.emplace_back(mk(a[k.second]+=p,k.second));
        else res1.emplace_back(k);
    }
    int len1=0,len2=0,aim1=res1.size()-1,aim2=res2.size()-1,ad=add[id],now=0;
    while(len1<=aim1||len2<=aim2){
        while(len1<=aim1&&(len2>aim2||res1[len1].first<=res2[len2].first)) num[id][now++]=res1[len1],len1++;
        while(len2<=aim2&&(len1>aim1||res1[len1].first>=res2[len2].first)) num[id][now++]=res2[len2],len2++;
    }
}
inline void update(int l,int r,int k){
    int p=pos[l],q=pos[r];
    if(p==q){
        rebuild(l,r,p,k);
        return;
    }
    rebuild(l,R[p],p,k);
    rebuild(L[q],r,q,k);
    for(int i=p+1;i<q;++i) add[i]+=k;
}
inline bool check(int mid,int l,int r,int k,int more){
    if(r<l) return more<k;
    int p=pos[l],q=pos[r],res=more;
    for(int i=p;i<=q;++i){
        if(num[i].back().first+add[i]<=mid){res+=num[i].size();continue;}
        if(num[i].front().first+add[i]>mid) continue;
        res+=upper_bound(num[i].begin(),num[i].end(),mk(mid-add[i],99999))-num[i].begin();
        if(res>=k) return false;
    }
    return res<k;
}
inline int query(int l,int r,int k){
    if(k>r-l+1) return -1;
    if(k==1){
        int res=INT_MAX,p=pos[l],q=pos[r];
        if(p==q){
            for(int i=l,ad=add[p];i<=r;++i) res=min(res,a[i]+ad);
            return res;
        }
        for(int i=l,ad=add[p];i<=R[p];++i) res=min(res,a[i]+ad);
        for(int i=L[q],ad=add[q];i<=r;++i) res=min(res,a[i]+ad);
        for(int i=p+1;i<q;++i) res=min(res,num[i].front().first+add[i]);
        return res;
    }
    else if(k==r-l+1){
        int res=-INT_MAX,p=pos[l],q=pos[r];
        if(p==q){
            for(int i=l,ad=add[p];i<=r;++i) res=max(res,a[i]+ad);
            return res;
        }
        for(int i=l,ad=add[p];i<=R[p];++i) res=max(res,a[i]+ad);
        for(int i=L[q],ad=add[q];i<=r;++i) res=max(res,a[i]+ad);
        for(int i=p+1;i<q;++i) res=max(res,num[i].back().first+add[i]);
        return res;
    }
    int left=INT_MAX,right=-INT_MAX,ans=0;
    vector<int> san(2*1000);
    int p=pos[l],q=pos[r],now=0;
    if(p==q){
        int res=0;
        for(auto i:num[p]){
            if(l<=i.second&&i.second<=r) res++;
            if(res==k) return i.first+add[p];
        }
    }
    else{
        int len1=0,len2=0,aim1=num[p].size()-1,aim2=num[q].size()-1,ad1=add[p],ad2=add[q];
        while(len1<=aim1||len2<=aim2){
            while(len1<=aim1&&(len2>aim2||num[p][len1].first+ad1<=num[q][len2].first+ad2)){
                if(l<=num[p][len1].second&&num[p][len1].second<=r){
                    int res=num[p][len1].first+ad1;
                    san[now++]=res;
                }
                ++len1;
            }
            while(len2<=aim2&&(len1>aim1||num[p][len1].first+ad1>=num[q][len2].first+ad2)){
                if(l<=num[q][len2].second&&num[q][len2].second<=r){
                    int res=num[q][len2].first+ad2;
                    san[now++]=res;
                }
                ++len2;
            }
        }
    }
    left=san[0],right=san[now-1];
    if(p==q-1) return san[k-1];
    for(int i=p+1,ad=add[i];i<q;++i,ad=add[i]) 
        left=min(left,num[i].front().first+ad),
        right=max(right,num[i].back().first+ad);
    l=R[p]+1,r=L[q]-1;
    while(left<=right){
        int mid=(0ll+left+right)>>1;
        int more=upper_bound(san.begin(),san.begin()+now,mid)-san.begin();
        if(check(mid,l,r,k,more)) left=mid+1;
        else ans=mid,right=mid-1;
    }
    return ans;
}
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
signed main(){
    // infile("in.in");outfile("out.out");
    n=read(),m=read();
    for(int i=1;i<=n;++i) a[i]=read();
    int siz=sqrt(n);len=n/siz;
    for(int i=1;i<=len;++i) L[i]=R[i-1]+1,R[i]=i*siz;
    // if(R[len]<n) len++,L[len]=R[len-1]+1,R[len]=n;
    R[len]=n;
    for(int i=1;i<=len;++i){
        for(int j=L[i];j<=R[i];++j){
            num[i].emplace_back(mk(a[j],j));
            pos[j]=i;
        }
        stable_sort(num[i].begin(),num[i].end());
    }
    while(m--){
        int op,l,r,k;op=read(),l=read(),r=read(),k=read();
        if(op==1){
            cout<<query(l,r,k)<<'\n';
            continue;
        }
        else update(l,r,k);
    }
}
posted @ 2024-08-19 19:22  CuFeO4  阅读(14)  评论(0编辑  收藏  举报