题面

传送门:https://www.luogu.org/problemnew/show/P2824


Solution

这题极其巧妙。

首先,如果直接做m次排序,显然会T得起飞。

注意一点:我们只需要找到一个数。

所以说,我们可以考虑一个绝妙的想法:我们可以用二分答案的方法缩小要找的数的区间

考虑二分一个值,判定p位置的数排序之后,p位置上的数是否>=mid

如果>=mid,则向右找,否则向左找。

怎么判定p位置的数排序之后是否>=mid呢?

考虑这样做:扫描一遍原数组,>=mid的数赋值为1,<mid的数赋值为0。

这样子,题目就变成了一个01序列排序。

这就很可做了,我们直接线段树维护之即可,我们只需要实现区间查询与区间赋值。

对于一个01区间排序,我们只需要知道这个区间有多少个0,多少个1,然后区间修改即可。

时间复杂度O(m*logn^2)

就酱,这题就可以切掉啦(ノ´▽`)ノ♪


Code

//Luogu  P2824 [HEOI2016/TJOI2016]排序
//Oct,19th,2018
//二分答案缩小范围+线段树妙题
#include<iostream>
#include<cstdio>
using namespace std;
long long read()
{
long long x=0,f=1; char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int N=30000+100;
int a[N],w[N];
struct SegmentTree
{
#define lson (now<<1)
#define rson (now<<1|1)
#define mid ((now_l+now_r)>>1)
static const int M=N<<2;
int sum[M][2],lazy[M];
inline void update(int now)
{
sum[now][0]=sum[lson][0]+sum[rson][0];
sum[now][1]=sum[lson][1]+sum[rson][1];
}
inline void pushdown(int now,int now_l,int now_r)
{
if(now_l==now_r)
{
lazy[now]=2;
return;
}
lazy[lson]=lazy[rson]=lazy[now];
sum[lson][lazy[now]]=mid-now_l+1,sum[lson][!lazy[now]]=0;
sum[rson][lazy[now]]=now_r-mid,sum[rson][!lazy[now]]=0;
lazy[now]=2;
}
void Build(int now,int now_l,int now_r)
{
sum[now][0]=sum[now][1]=0;
lazy[now]=2;
if(now_l==now_r)
{
sum[now][w[now_l]]++;
return;
}
Build(lson,now_l,mid);
Build(rson,mid+1,now_r);
update(now);
}
void Change(int L,int R,int x,int now,int now_l,int now_r)
{
if(L>R) return;
if(lazy[now]!=2) pushdown(now,now_l,now_r);
if(now_l>=L and now_r<=R)
{
sum[now][x]=now_r-now_l+1,sum[now][!x]=0;
lazy[now]=x;
return;
}
if(L<=mid) Change(L,R,x,lson,now_l,mid);
if(R>mid) Change(L,R,x,rson,mid+1,now_r);
update(now);
}
int Query(int L,int R,int x,int now,int now_l,int now_r)
{
if(lazy[now]!=2) pushdown(now,now_l,now_r);
if(now_l>=L and now_r<=R)
return sum[now][x];
int ans=0;
if(L<=mid) ans+=Query(L,R,x,lson,now_l,mid);
if(R>mid) ans+=Query(L,R,x,rson,mid+1,now_r);
return ans;
}
#undef lson
#undef rson
#undef mid
}sgt;
struct OP
{
int type,L,R;
}op[N];
int n,m,p;
bool Check(int x)
{
for(int i=1;i<=n;i++)
if(a[i]>=x) w[i]=1;
else w[i]=0;
sgt.Build(1,1,n);
for(int i=1;i<=m;i++)
{
int cnt0=sgt.Query(op[i].L,op[i].R,0,1,1,n),cnt1=op[i].R-op[i].L+1-cnt0;
if(op[i].type==0)
sgt.Change(op[i].L,op[i].L+cnt0-1,0,1,1,n),
sgt.Change(op[i].L+cnt0,op[i].R,1,1,1,n);
else
sgt.Change(op[i].L,op[i].L+cnt1-1,1,1,1,n),
sgt.Change(op[i].L+cnt1,op[i].R,0,1,1,n);
}
if(sgt.Query(p,p,1,1,1,n)==1) return true;
return false;
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<=m;i++)
op[i].type=read(),op[i].L=read(),op[i].R=read();
p=read(); int L=0,R=n+100,ans=0;
while(L<=R)
{
int mid=(L+R)/2;
if(Check(mid)==true)
ans=max(ans,mid),L=mid+1;
else
R=mid-1;
} printf("%d",ans);
return 0;
}

最新文章

  1. [LeetCode] Sum Root to Leaf Numbers 求根到叶节点数字之和
  2. 实体类和DataTable的转换
  3. duilib\utils\utils.h(251) : error C2504: “VARIANT”: 未定义基类
  4. O(1)时间内删除指定链表结点
  5. Case When PK PIVOT
  6. 2008年NOI全国竞赛 假面舞会
  7. 图的最短路径问题————树上奶牛(tree.cpp)
  8. 46. Permutations(medium, backtrack, 重要)
  9. laravel 模型操作
  10. 杨学明老师推出全新课程--《敏捷开发&amp;IPD和敏捷开发结合的实践》
  11. MVC下 Area和Web同名的Controller问题
  12. xshell 利用密钥登录
  13. 配置私有SSH
  14. ASP.NET 数据绑定到列表控件
  15. python 之socket
  16. μC/OS-Ⅱ在C8051F060上的移植及其应用
  17. zookeeper的c API 单线程与多线程问题 cli_st和cli_mt
  18. nexus3 搭建maven远程仓库
  19. 网站运维之 使用IIS日志分析器1.03.exe进行IIS服务器日志分析
  20. IOS Intro - Write file

热门文章

  1. gerrit安装配置记录
  2. springboot项目打包瘦身
  3. 【题解】Computer Network
  4. Numpy中的shape和reshape()
  5. Centos最小化安装后,不能使用yum命令的解决办法
  6. 带UI 的小初高数学学习系统 —结对编程项目总结
  7. Spring Boot入门系列(二十)快速打造Restful API 接口
  8. A4988两相四线步进电机驱动模块使用经验
  9. 如何在Windows7安装U盘中加入USB3.0驱动的支持
  10. day20 Pyhton学习 面向对象-成员