[JXOI2017] 加法 题解
[JXOI2017] 加法
最小值最大,一眼二分。贪心地,每次尽量对包含当前序列最小值的区间做加法操作,也就是说,对于当前二分的答案
从左到右地考虑答案。我们认为当前点之前的所有值都已经满足条件,于是我们只需考虑每次区间对当前点之后答案造成的贡献。于是我们将所有区间按左端点为第一关键字排序,而在左端点相同的所有区间当中,我们选择右端点最靠右的区间,以覆盖更多的元素。
每一次从
需要一个支持区间修改、单点查询的数据结构,线段树和树状数组皆可。
#include<bits/stdc++.h>
#define fw fwrite(obuf,p3-obuf,1,stdout)
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define putchar(x) (p3-obuf<1<<20?(*p3++=(x)):(fw,p3=obuf,*p3++=(x)))
using namespace std;
char buf[1<<20],obuf[1<<20],*p1=buf,*p2=buf,*p3=obuf,str[20<<2];
int read(){
int x=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x;
}
template<typename T>
void write(T x,char sf='\n'){
if(x<0)putchar('-'),x=~x+1;
int top=0;
do str[top++]=x%10,x/=10;while(x);
while(top)putchar(str[--top]+48);
if(sf^'#')putchar(sf);
}
using ll=long long;
constexpr int MAXN=2e5+5;
int T,n,m,k,A;
ll a[MAXN];
struct{
ll st[MAXN<<2],lazy[MAXN<<2];
#define lp p<<1
#define rp p<<1|1
#define mid ((s+t)>>1)
void build(int s,int t,int p){
st[p]=lazy[p]=0;
if(s==t)return st[p]=a[s],void();
build(s,mid,lp),build(mid+1,t,rp);
st[p]=st[lp]+st[rp];
}
void pushdown(int s,int t,int p){
if(!lazy[p]) return;
st[lp]+=(mid-s+1)*lazy[p],st[rp]+=(t-mid)*lazy[p];
lazy[lp]+=lazy[p],lazy[rp]+=lazy[p];
lazy[p]=0;
}
void mdf(int l,int r,ll k,int s=1,int t=n,int p=1){
if(l<=s&&t<=r) return st[p]+=(t-s+1)*k,lazy[p]+=k,void();
pushdown(s,t,p);
if(l<=mid) mdf(l,r,k,s,mid,lp);
if(mid<r) mdf(l,r,k,mid+1,t,rp);
st[p]=st[lp]+st[rp];
}
ll sum(int x,int s=1,int t=n,int p=1){
if(s==t) return st[p];
pushdown(s,t,p);
if(x<=mid) return sum(x,s,mid,lp);
return sum(x,mid+1,t,rp);
}
#undef mid
}ST;
struct SH{
int l,r;
bool operator<(const SH&x)const{
return r<x.r;
}
}p[MAXN],t;
bool check(ll x){
priority_queue<SH>q;
ST.build(1,n,1);
int lst=1,cnt=0;
for(int i=1;i<=n;++i){
while(lst<=m&&p[lst].l<=i) q.emplace(p[lst++]);
while(!q.empty()&&ST.sum(i)<x){
do t=q.top(),q.pop();
while(!q.empty()&&t.r<i);
if(t.r<i||++cnt>k) return 0;
ST.mdf(t.l,t.r,A);
}
if(ST.sum(i)<x) return 0;
}
return 1;
}
int main(){
T=read();
while(T--){
n=read(),m=read(),k=read(),A=read();
ll l=2e18,r=0;
for(int i=1;i<=n;++i) a[i]=read(),l=min(l,a[i]),r=max(r,a[i]);
r+=k*A;
for(int i=1;i<=m;++i) p[i]={read(),read()};
sort(p+1,p+m+1,[&](const SH&x,const SH&y){
return x.l<y.l;
});
ll mid,ans=l;
while(l<=r){
mid=(l+r)>>1;
if(check(mid)) l=mid+1,ans=mid;
else r=mid-1;
}
write(ans);
}
return fw,0;
}
即得易见平凡,仿照上例显然。留作习题答案略,读者自证不难。
反之亦然同理,推论自然成立。略去过程 ,由上可知证毕。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】