题解-学习心得
2026-10-19 09:29:53
发布于:广东
一、题意
自行理解。
二、思路
1、观察
-
题目没有要求输出整个序列,而是询问单点,猜想可能不用知道整个序列即可。
-
可以转换二分。二分需要一个判定,设最终 位置的真实值为 ,令 表示 位置上的值是否 。当 时,, 为真;当 时,, 为假。所以可行 的集合是前缀 ,具有单调性,。
-
可以令 表示 位置上的值是否 ,接下来要解决的是。
-
既然判定只依赖元素和 的大小关系,而排序又难以直接维护,不如把序列按阈值 二值化,也就是 : 记 ,否则记 。这样排序就变得简单了。
2、细节
整个 数组是这样求出的:令 为 ,否则为 ;这样后续判断 位置是否为 即可。
序列排序只需:升序把 赋 、 赋 ;降序把 赋 、 赋 。,线段树维护区间和与区间覆盖即可。
二分时 为真则 ,,它就是 。
3、时间复杂度
每次 为 ,二分 次,总复杂度为 ,可以通过。
4、易错点
- : 为真时 ,找最大可行 。
- 要区分“无标记”和“赋 ”,建议用 表示无标记。
- ,避免 时越界。
三、代码
#include<iostream>
#define ls 2*u
#define rs 2*u+1
using namespace std;
const int N = 1e5;
struct option{int op,l,r;}box[N+5];
int n,num,q,a[N+5],sol[N+5];
struct Seg_tree
{
int sum[N*4],tag[N*4];
void seg_sol(int u)
{
sum[u] = sum[ls]+sum[rs];
}
void build(int u,int l,int r)
{
tag[u] = -1;
if(l==r)
{
sum[u] = sol[l];
return ;
}
int mid = (l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
seg_sol(u);
}
void apply(int u,int l,int r,int val)
{
tag[u] = val;
sum[u] = (r-l+1)*val;
}
void pushdown(int u,int l,int r)
{
if(tag[u]==-1) return ;
int mid = (l+r)>>1;
apply(ls,l,mid,tag[u]);
apply(rs,mid+1,r,tag[u]);
tag[u] = -1;
}
void update(int u,int l,int r,int ql,int qr,int val)
{
if(r<ql||l>qr) return ;
if(ql<=l&&r<=qr)
{
apply(u,l,r,val);
return ;
}
int mid = (l+r)>>1;
pushdown(u,l,r);
update(ls,l,mid,ql,qr,val);
update(rs,mid+1,r,ql,qr,val);
seg_sol(u);
}
int query(int u,int l,int r,int ql,int qr)
{
if(r<ql||l>qr) return 0;
if(ql<=l&&r<=qr) return sum[u];
int mid = (l+r)>>1;
pushdown(u,l,r);
return query(ls,l,mid,ql,qr)+query(rs,mid+1,r,ql,qr);
}
}xt;
bool check(int mid)
{
for(int i=1;i<=n;i++)
{
if(a[i]>=mid) sol[i] = 1;
else sol[i] = 0;
}
xt.build(1,1,n);
for(int i=1;i<=num;i++)
{
int op = box[i].op,l = box[i].l,r = box[i].r;
int cnt = xt.query(1,1,n,l,r);
if(l>r) continue;
if(op==0)
{
xt.update(1,1,n,l,r-cnt,0);
xt.update(1,1,n,r-cnt+1,r,1);
}
else
{
xt.update(1,1,n,l,l+cnt-1,1);
xt.update(1,1,n,l+cnt,r,0);
}
}
return xt.query(1,1,n,q,q)==1;
}
int main()
{
cin>>n>>num;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=num;i++)
{
int op,l,r;
cin>>op>>l>>r;
box[i] = {op,l,r};
}
cin>>q;
int l = 1;
int r = n+1;
while(r-l>1)
{
int mid = (l+r)>>1;
if(check(mid)) l = mid;
else r = mid;
}
cout<<l;
return 0;
}
四、总结&trick
1、查询改成判定
这个应该是本题的难点,主要是发现了“单点”与“单调性”。
2、 化
我认为可以先需要离散化,后续发现直接 即可。
这里空空如也
















有帮助,赞一个