Best Subsequence 题解
有一个经典 trick。我们先二分答案,然后假设当前二分的值为
比较显然的是:
显然我们选两个
我们考虑一下我们的二分,check 的时候需要找到区间内所有的
先考虑
接下来考虑两个
我们考虑在每个点上维护信息
发现有一段
考虑判断有多少个
现在只需要解决跨段的东西,直接找到这一坨东西的最小值加上两端点的最大值看一下会不会造成贡献即可。
注意特判
AC code:
#include<bits/stdc++.h>
#define int long long
#define N 100005
#define pii pair<int,int>
#define pcc pair<char,char>
#define x first
#define y second
#define pct __builtin_popcount
#define mod 998244353
#define inf (2e9+10)
#define pi acos(-1)
#define eps 1e-2
using namespace std;
int T=1,n,q,a[N],p[N],b[N],rt[N];
struct node{
int a,b,c;
bool operator<(const node &t)const{
if(a!=t.a)return a<t.a;
if(b!=t.b)return b<t.b;
return c<t.c;
}
};
vector<node>e;
struct sgt{
int tr[N<<2];
void pushup(int u){
tr[u]=min(tr[u<<1],tr[u<<1|1]);
}
void build(int u,int l,int r){
if(l==r){
tr[u]=a[l];
return;
}
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
int qry(int u,int l,int r,int L,int R){
if(l>=L&&r<=R)return tr[u];
int mid=l+r>>1;
int res=inf;
if(L<=mid)res=min(res,qry(u<<1,l,mid,L,R));
if(R>mid)res=min(res,qry(u<<1|1,mid+1,r,L,R));
return res;
}
int qryl(int u,int l,int r,int x,int v){
if(tr[u]>v)return n+1;
if(l==r)return l;
int mid=l+r>>1;
if(x>mid)return qryl(u<<1|1,mid+1,r,x,v);
int res=qryl(u<<1,l,mid,x,v);
if(res!=n+1)return res;
else return qryl(u<<1|1,mid+1,r,x,v);
}
int qryr(int u,int l,int r,int x,int v){
if(tr[u]>v)return 0;
if(l==r)return l;
int mid=l+r>>1;
if(x<=mid)return qryr(u<<1,l,mid,x,v);
int res=qryr(u<<1|1,mid+1,r,x,v);
if(res!=0)return res;
else return qryr(u<<1,l,mid,x,v);
}
}tr;
struct dsgt{
int ls[N<<6],rs[N<<6],s[N<<6],val[N<<6],cnt,tot;
void pushup(int &u,int las,int l,int r,int x,int v){
u=++cnt;
s[u]=s[las]+v;
ls[u]=ls[las];
rs[u]=rs[las];
if(l==r)return;
int mid=l+r>>1;
if(x<=mid)pushup(ls[u],ls[las],l,mid,x,v);
else pushup(rs[u],rs[las],mid+1,r,x,v);
}
void build(){
sort(e.begin(),e.end());
int now=0;
for(auto it:e){
if(!tot||val[tot]!=it.a)val[++tot]=it.a;
pushup(rt[tot],now,1,n,it.b,it.c);
now=rt[tot];
}
}
int qry(int u,int l,int r,int L,int R){
if(!u)return 0;
if(l>=L&&r<=R)return s[u];
int mid=l+r>>1;
int res=0;
if(L<=mid)res+=qry(ls[u],l,mid,L,R);
if(R>mid)res+=qry(rs[u],mid+1,r,L,R);
return res;
}
int find(int v,int L,int R){
int u=upper_bound(val+1,val+tot+1,v)-val;
return qry(rt[u-1],1,n,L,R);
}
}dtr;
void solve(int cs){
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>a[i];
p[i]=i;
}
sort(p+1,p+n+1,[&](int x,int y){
return a[x]<a[y];
});
tr.build(1,1,n);
set<int>s;
for(int cur=1;cur<=n;cur++){
int i=p[cur];
auto it=s.lower_bound(i);
e.push_back({a[i]*2,i,1});
int l=0,r=n+1;
if(it!=s.end())r=*it;
if(it!=s.begin())l=*(--it);
if(l!=0){
if(b[l]<a[i]*2){
e.push_back({b[l],l,1});
e.push_back({a[i]*2,l,-1});
}
b[l]=inf;
if(l+1<i)b[l]=tr.qry(1,1,n,l+1,i-1)+a[i];
}
b[i]=inf;
if(i+1<r)b[i]=tr.qry(1,1,n,i+1,r-1)+a[i];
s.insert(i);
}
dtr.build();
while(q--){
int l,r,k;
cin>>l>>r>>k;
int cur=tr.qry(1,1,n,l,r)*2;
if(k==1){
cout<<cur<<'\n';
continue;
}
int L=cur,R=inf-10,res=R;
while(L<=R){
int mid=L+R>>1;
int pl=tr.qryl(1,1,n,l,mid/2);
int pr=tr.qryr(1,1,n,r,mid/2);
int sum=dtr.find(mid,pl,pr-1)+1;
int now=inf;
if(l<pl)now=min(now,tr.qry(1,1,n,l,pl-1));
if(r>pr)now=min(now,tr.qry(1,1,n,pr+1,r));
if(now<inf&&now+max(a[pl],a[pr])<=mid)sum++;
if(sum>=k){
res=mid;
R=mid-1;
}
else L=mid+1;
}
cout<<res<<'\n';
}
}
void solution(){
/*
nothing here
*/
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// init();
// cin>>T;
for(int cs=1;cs<=T;cs++){
solve(cs);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】