由乃打扑克
题目链接 : 由乃打扑克
既然是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不可能这么简单。
需要考虑一些优化才可以过掉这道题。
-
将散块单独拿出来,组成一个新的块。这样可以优化掉一部分
-
对于整块的最大值小于二分出的答案,直接加上整块长度
-
对于整块的最小值大于二分出的答案的,直接跳过
加上这几个优化就可以不加卡常轻松过掉这道题了
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);
}
}
__________________________________________________________________________________________
本文来自博客园,作者:CuFeO4,转载请注明原文链接:https://www.cnblogs.com/hzoi-Cu/p/18367944