BZOJ 4552(二分+线段树+思维)
题面
分析
此题是道好题!
首先要跳出思维定势,不是去想如何用数据结构去直接维护排序过程,而是尝试二分a[p]的值
设二分a[p]的值为x
我们将大于x的数标记为1,小于等于x的数标记为0
则整个序列只由01组成,记为b
将一个区间升序排序,则相当于将1全部移到右边,0全部移到左边,降序排序反之
例:
a={1,6,5,2,4,3}.x=4
标记后的序列b为{0,1,1,0,0,0}
此时对[1,5]进行升序排序,a={1,2,4,5,6,3}
标记后的序列b为{0,0,0,1,1,0}
因此可以用线段树维护标记后的序列,直接区间求和得到1的个数,再区间更新即可
如果排完序后b[p]=0,则说明a[p]<=x,继续减小x
否则增大x
代码
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 100005 using namespace std; int n,m,qa; struct node { int l; int r; int v; int mark; int len() { return r-l+1; } } tree[maxn<<2]; int a[maxn]; struct sort_seg { int l; int r; int type; } q[maxn]; void push_up(int pos) { tree[pos].v=tree[pos<<1].v+tree[pos<<1|1].v; } void build(int l,int r,int pos,int middle) { tree[pos].l=l; tree[pos].r=r; tree[pos].v=0; tree[pos].mark=-1; if(l==r) { tree[pos].v=(a[l]>middle); return; } int mid=(tree[pos].l+tree[pos].r)>>1; build(l,mid,pos<<1,middle); build(mid+1,r,pos<<1|1, middle); push_up(pos); } void push_down(int pos) { if(tree[pos].mark!=-1) { tree[pos<<1].mark=tree[pos].mark; tree[pos<<1|1].mark=tree[pos].mark; tree[pos<<1].v=tree[pos].mark*tree[pos<<1].len(); tree[pos<<1|1].v=tree[pos].mark*tree[pos<<1|1].len(); tree[pos].mark=-1; } } void update(int L,int R,int v,int pos) { if(R<tree[pos].l||L>tree[pos].r) return; if(L<=tree[pos].l&&R>=tree[pos].r) { tree[pos].v=v*tree[pos].len(); tree[pos].mark=v; return; } push_down(pos); int mid=(tree[pos].l+tree[pos].r)>>1; if(L<=mid) update(L,R,v,pos<<1); if(R>mid) update(L,R,v,pos<<1|1); push_up(pos); } int query(int L,int R,int pos) { if(R<tree[pos].l||L>tree[pos].r) return 0; if(L<=tree[pos].l&&R>=tree[pos].r) { return tree[pos].v; } push_down(pos); int mid=(tree[pos].l+tree[pos].r)>>1; int ans=0; if(L<=mid) ans+=query(L,R,pos<<1); if(R>mid) ans+=query(L,R,pos<<1|1); return ans; } int check(int x) { build(1,n,1,x); for(int i=1; i<=m; i++) { int sum=query(q[i].l,q[i].r,1); if(q[i].type==0) { update(q[i].l,q[i].r-sum,0,1); update(q[i].r-sum+1,q[i].r,1,1); } else { update(q[i].l,q[i].l+sum-1,1,1); update(q[i].l+sum,q[i].r,0,1); } } if(query(qa,qa,1)==1) return 0; else return 1; } int main() { scanf("%d %d",&n,&m); for(int i=1; i<=n; i++) { scanf("%d",&a[i]); } for(int i=1; i<=m; i++) { scanf("%d %d %d",&q[i].type,&q[i].l,&q[i].r); } int l=1,r=n; int ans=n+1; scanf("%d",&qa); while(l<=r) { int mid=(l+r)>>1; if(check(mid)) { ans=min(ans,mid); r=mid-1; } else { l=mid+1; } } printf("%d\n",ans); }
版权声明:因为我是蒟蒻,所以请大佬和神犇们不要转载(有坑)的文章,并指出问题,谢谢
· C#高性能开发之类型系统:从 C# 7.0 到 C# 14 的类型系统演进全景
· 从零实现富文本编辑器#3-基于Delta的线性数据结构模型
· 记一次 .NET某旅行社酒店管理系统 卡死分析
· 长文讲解 MCP 和案例实战
· Hangfire Redis 实现秒级定时任务,使用 CQRS 实现动态执行代码
· C#高性能开发之类型系统:从 C# 7.0 到 C# 14 的类型系统演进全景
· 管理100个小程序-很难吗
· 基于Blazor实现的运输信息管理系统
· 使用这个工具,基于代码仓库直接生成教程文档,感觉比我自己写的还好
· 如何统计不同电话号码的个数?—位图法