P5356 [Ynoi2017] 由乃打扑克 题解
纪念一下人生第一道 Ynoi 题目链接
题意
是个人都看得懂吧。。。。。。
solution
看到 Ynoi,想到什么?
- 分块
- 卡常
你猜对了,这题又是分块。
在数列分块入门 2中我们已经学会了询问区间内小于某个值 $x$ 的元素个数。
很容易想到二分元素的值域,如果小于等于 $x$ 的小于 $k$,那么就往大枚举,否则往下枚举,更新答案。
code:
while(l <= r){
int mid = (l+r)>>1;
int check = query(dl, dr, mid);
if(check < k) l = mid+1;
else r = mid-1, ans = mid;
}
看着非常地正确。但时间复杂度是 $O(m \sqrt{n} \log{n} \log{v})$
很遗憾,被我卡了 -lxl
优化
但是作为最简单的Ynoi,它是可以被以上暴力c过去的。
加上一下优化就可以过了:
- 二分边界取区间最大和最小值
- 查询时,如果当前区间的最大值小于 $k$ 那么就可以直接加上区间大小,如果当前区间最小值大于 $k$ 那么就不用再去计算它了。
- 玄学的块长
代码
#include<cmath>
#include<cstdio>
#include<algorithm>
const int MAX = 100005;
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define rg register
static char buf[1000000],*p1=buf,*p2=buf;
#define getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++
inline int read(){int x=0,f=1;char c=getchar();while(c<'0' || c>'9'){if(c=='-') f=-1;c=getchar();}while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+c-48;c=getchar();}return x*f;}
inline void write(int x){static char buf[20];static int len=-1;if(x<0)putchar('-'),x=-x;do buf[++len]=x%10,x/=10;while(x);while(len>=0)putchar(buf[len--]+48);}
int a[MAX];
int b[MAX];
int id[MAX];
int pls[1005];
int L[1005], R[1005];
inline void add(int l, int r, int c){
int p = id[l], q = id[r];
if(p == q){
for(rg int i = l; i <= r; i++) b[i] += c;
for(rg int i = L[p]; i <= R[p]; i++){
a[i] = b[i];
}
std::sort(a+L[p], a+R[p]+1);
}else{
for(rg int i = l; i <= R[p]; ++i) b[i] += c;
for(rg int i = L[p]; i <= R[p]; ++i) a[i] = b[i];
std::sort(a+L[p], a+R[p]+1);
for(rg int i = p+1; i <= q-1; ++i) pls[i] += c;
for(rg int i = r; i >= L[q]; --i) b[i] += c;
for(rg int i = L[q]; i <= R[q]; ++i) a[i] = b[i];
std::sort(a+L[q], a+R[q]+1);
}
}
inline int query(int l, int r, int c){
int p = id[l], q = id[r];
int ans = 0;
if(p == q){
if(a[R[p]] + pls[p] <= c) ans += r-l+1;
else if(a[L[p]] + pls[p] <= c) for(int i = l; i <= r; ++i) ans+=b[i] + pls[p] <= c;
}else{
if(a[R[p]] + pls[p] <= c) ans += R[p]-l+1;
else if(a[L[p]] + pls[p] <= c) for(int i = l; i <= R[p]; i++) ans+=b[i] + pls[p] <= c;
int u,v,mid;
for(rg int i = p+1; i <= q-1; ++i){
if(a[L[i]]+pls[i]>c)continue;
if(a[R[i]]+pls[i]<=c){
ans+=R[i]-L[i]+1;
continue;
}
u=L[i],v=R[i],mid;
while(u<v){
int mid=u+((v-u)>>1)+1;
if(a[mid]+pls[i]<=c)u=mid;
else v=mid-1;
}
ans+=u-(i-1)*(R[i]-L[i]+1);
}
if(a[R[q]] + pls[q] <= c) ans += r - L[q] + 1;
else if(a[L[q]] + pls[q] <= c) for(int i = L[q]; i <= r; i++) ans+=b[i] + pls[q] <= c;
}
return ans;
}
inline int getmax(int l, int r){
int p = id[l], q = id[r];
int ans = -0x3f3f3f3f;
if(p == q){
for(rg int i = l; i <= r; i++) ans = max(ans, b[i]+pls[p]);
}else{
if(a[R[p]]+pls[p]>ans)for(rg int i = l; i <= R[p]; i++) ans = max(ans, b[i]+pls[p]);
for(rg int i = p+1; i <= q-1; i++) ans = max(ans, a[R[i]]+pls[i]);
if(a[R[q]]+pls[q]>ans)for(rg int i = L[q]; i <= r; i++) ans = max(ans, b[i]+pls[q]);
}
return ans;
}
inline int getmin(int l, int r){
int p = id[l], q = id[r];
int ans = 0x3f3f3f3f;
if(p == q){
for(rg int i = l; i <= r; i++) ans = min(ans, b[i]+pls[p]);
}else{
if(a[L[p]]+pls[p]<ans)for(rg int i = l; i <= R[p]; ++i) ans = min(ans, b[i]+pls[p]);
for(rg int i = p+1; i <= q-1; ++i) ans = min(ans, a[L[i]]+pls[i]);
if(a[L[q]]+pls[q]<ans)for(rg int i = L[q]; i <= r; ++i) ans = min(ans, b[i]+pls[q]);
}
return ans;
}
int c[2007];
inline int ask(int dl, int dr, int k){
if(dr-dl+1 < k or k < 1) return -1;
int l = getmin(dl, dr), r = getmax(dl, dr);
if(id[dl] == id[dr]){
for(int i = 0; i <= dr - dl; ++i){
c[i] = b[i+dl];
}
std::sort(c, c+dr-dl+1);
return c[k-1]+pls[id[dl]];
}
int ans = 0;
while(l <= r){
int mid = l+((r-l)>>1);
int check = query(dl, dr, mid);
if(check < k) l = mid+1;
else r = mid-1, ans = mid;
}
return ans;
}
signed main(){
int n = read(), m = read();
for(rg int i = 1; i <= n; ++i) a[i] = read(), b[i] = a[i];
int t(200);
for(int i=1;i<=n;i++)id[i]=(i-1)/t+1;
for(int i=1;i<=id[n];i++)L[i]=(i-1)*t+1,R[i]=i*t;
R[id[n]]=n;
for(rg int i = 1; i <= id[n]; ++i){
std::sort(a+L[i], a+R[i]+1);
}
int op,l,r,k;
while(m--){
op = read(), l = read(), r = read(), k = read();
if(op-1) add(l, r, k);
else write(ask(l, r, k)), putchar('\n');
}
return 0;
}