LGP2824 [HETS 2016||TJTS 2016] 排序 学习笔记
LGP2824 [HETS 2016||TJTS 2016] 排序 学习笔记
题意简述
给出一个长为
0 l r
表示将区间 的数字按升序排序;1 l r
表示将区间 的数字按降序排序。
这里的区间指的是下标而非值。
最后一次询问,询问上述所有操作依次完成后 的值。
做法解析
发现只有一次询问,而且还是在所有操作之后。套路地考虑二分答案
这样子排序操作因为只有
然后做完了。时间复杂度
代码实现
#include <bits/stdc++.h>
using namespace std;
namespace obasic{
template <typename _T>
void readi(_T &x){
_T k=1;x=0;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')k=-1;
for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-'0';
x*=k;return;
}
template <typename _T>
void writi(_T x){
if(x<0)putchar('-'),x=-x;
if(x>9)writi(x/10);
putchar(x%10+'0');
}
};
using namespace obasic;
const int MaxN=1e5+5;
int N,M,A[MaxN],Q;
struct oper{int t,l,r;}P[MaxN];
struct SegTree{
int cl[MaxN<<2],cr[MaxN<<2],cmid[MaxN<<2];
int sum[MaxN<<2],tag[MaxN<<2];
int ls(int p){return p<<1;}
int rs(int p){return (p<<1)|1;}
void ainit(int p,int l,int r){
cl[p]=l,cr[p]=r,cmid[p]=(l+r)>>1;if(l==r)return;
ainit(ls(p),l,cmid[p]);ainit(rs(p),cmid[p]+1,r);
}
void pushup(int p){
sum[p]=sum[ls(p)]+sum[rs(p)];
}
void build(int p,int v){
tag[p]=-1;
if(cl[p]==cr[p]){sum[p]=(A[cl[p]]>=v?1:0);return;}
build(ls(p),v),build(rs(p),v);pushup(p);
}
void maketag(int p,int v){
sum[p]=v*(cr[p]-cl[p]+1),tag[p]=v;
}
void pushdown(int p){
if(tag[p]==-1||cl[p]==cr[p])return;
maketag(ls(p),tag[p]);
maketag(rs(p),tag[p]);
tag[p]=-1;
}
int getsum(int p,int dl,int dr){
if(dl<=cl[p]&&cr[p]<=dr)return sum[p];
pushdown(p);int res=0;
if(dl<=cmid[p])res+=getsum(ls(p),dl,dr);
if(dr>cmid[p])res+=getsum(rs(p),dl,dr);
pushup(p);return res;
}
void update(int p,int dl,int dr,int v){
if(dl<=cl[p]&&cr[p]<=dr){maketag(p,v);return;}
pushdown(p);
if(dl<=cmid[p])update(ls(p),dl,dr,v);
if(dr>cmid[p])update(rs(p),dl,dr,v);
pushup(p);
}
}SegTr;
bool check(int lim){
SegTr.build(1,lim);
for(int i=1;i<=M;i++){
auto [pt,pl,pr]=P[i];
int cnt=SegTr.getsum(1,pl,pr);
if(cnt==pr-pl+1)continue;
if(pt==0){
SegTr.update(1,pl,pr-cnt,0);
SegTr.update(1,pr-cnt+1,pr,1);
}
if(pt==1){
SegTr.update(1,pl,pl+cnt-1,1);
SegTr.update(1,pl+cnt,pr,0);
}
}
return SegTr.getsum(1,Q,Q);
}
int main(){
readi(N),readi(M);SegTr.ainit(1,1,N);
for(int i=1;i<=N;i++)readi(A[i]);
for(int i=1;i<=M;i++)readi(P[i].t),readi(P[i].l),readi(P[i].r);
readi(Q);int bl=1,br=N,bmid,ans;
while(bl<=br){
bmid=(bl+br)>>1;
if(check(bmid))ans=bmid,bl=bmid+1;
else br=bmid-1;
}
writi(ans);
return 0;
}
反思总结
如果题目问进行了一堆比较大小相关操作后只跟了一次询问,考虑二分这个询问的结果,然后将大于等于它的东西设为
另外如果线段树要修改或查询由比较活跃的变量决定的区间的话,注意判空!!!
标签:
线段树
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!