排序:二分线段树神仙好题。

trick

我们可以二分值域,然后把大于等于它的数标记成 \(1\),其他标记为 \(0\)(有些题需要标记成 \(-1\) ),然后根据这个来 check 方案是否可行,这通常通过判断某个数是否是 \(1\) 来实现。本质上其实就是 check 大于等于它的数能否成为答案(大于等于它的数为 \(1\))。常用于查找中位数、第 \(k\) 个数,以及大小关系只注重两种(比如只区分大于 \(7\) 和小于 \(7\) ,而大于 \(7\) 的数之间的大小无关的情况)。

运用到和这道题类似的 trick 的题还有这几道:最大战力Median Pyramid Hard

思路

知道这个 trick 之后这题就迎刃而解了。

因为这是个排列,所以我们直接二分 \(1\) 到 \(n\) 中的数,把大于等于它的数标记成 \(1\) ,其余为 \(0\) 。

在 check 中,我们用线段树维护一个 \(01\) 序列,处理好区间查询与区间的 \(01\) 排序。

最后 check 时查询线段树上的第 \(q\) 项是多少,如果是 \(1\) 就说明取的值小于等于答案(因为此时标记为 \(1\) 的太多了),否则就说明我们取的值比答案大(标记为 \(1\) 的太少了)。最后输出最后一个第 \(q\) 位是 \(1\) 的数即可。

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define lc (p<<1)
#define rc ((p<<1)|1)
using namespace std;
typedef long long ll;
typedef pair<int,int> pi;
const int N=100005;
int n,m,a[N],ql[N],qr[N],qop[N],q;
struct node{
int l,r;
int sum1,sum0;
int tag;
}tr[4*N];
void pushup(node &p,node ls,node rs)
{
p.sum1=ls.sum1+rs.sum1;
p.sum0=ls.sum0+rs.sum0;
}
void pd(int p,int op)
{
node &t=tr[p];
if(op==0)
{
t.sum1=0;
t.sum0=t.r-t.l+1;
t.tag=0;
}
if(op==1)
{
t.sum0=0;
t.sum1=t.r-t.l+1;
t.tag=1;
}
}
void pushdown(int p)
{
if(tr[p].tag==0)
{
pd(lc,0);
pd(rc,0);
}
if(tr[p].tag==1)
{
pd(lc,1);
pd(rc,1);
}
tr[p].tag=-1;
}
void build(int p,int ln,int rn,int x)
{
tr[p]={ln,rn,a[ln]>=x,a[ln]<x,-1};
if(ln==rn)return;
int mid=(ln+rn)>>1;
build(lc,ln,mid,x);
build(rc,mid+1,rn,x);
pushup(tr[p],tr[lc],tr[rc]);
}
void update(int p,int ln,int rn,int op)
{
if(ln<=tr[p].l&&tr[p].r<=rn)
{
pd(p,op);
return;
}
pushdown(p);
int mid=(tr[p].l+tr[p].r)>>1;
if(ln<=mid)update(lc,ln,rn,op);
if(rn>=mid+1)update(rc,ln,rn,op);
pushup(tr[p],tr[lc],tr[rc]);
}
node query(int p,int ln,int rn)
{
if(ln<=tr[p].l&&tr[p].r<=rn)return tr[p];
int mid=(tr[p].l+tr[p].r)>>1;
pushdown(p);
if(rn<=mid)return query(lc,ln,rn);
if(ln>=mid+1)return query(rc,ln,rn);
node tmp;
pushup(tmp,query(lc,ln,rn),query(rc,ln,rn));
return tmp;
}
bool check(int x)
{
build(1,1,n,x);
// for(int i=1;i<=n;i++)cout<<query(1,i,i).sum1<<' ';
// cout<<endl;
for(int i=1;i<=m;i++)
{
node res=query(1,ql[i],qr[i]);
int sum1=res.sum1,sum0=res.sum0;
if(qop[i]==0)
{
if(ql[i]<=ql[i]+sum0-1)update(1,ql[i],ql[i]+sum0-1,0);
if(ql[i]+sum0<=qr[i])update(1,ql[i]+sum0,qr[i],1);
}
else
{
if(ql[i]<=ql[i]+sum1-1)update(1,ql[i],ql[i]+sum1-1,1);
if(ql[i]+sum1<=qr[i])update(1,ql[i]+sum1,qr[i],0);
}
// for(int i=1;i<=n;i++)cout<<query(1,i,i).sum1<<' ';
// cout<<endl;
}
return (query(1,q,q).sum1==1);
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=m;i++)cin>>qop[i]>>ql[i]>>qr[i];
cin>>q;
int l=1,r=n,mid;
while(l<r)
{
mid=(l+r+1)>>1;
if(check(mid))l=mid;
else r=mid-1;
// cout<<"l="<<l<<" ; r="<<r<<" ; mid="<<mid<<endl;
// for(int i=1;i<=n;i++)cout<<query(1,i,i).sum1<<' ';
// cout<<endl<<endl;
}
cout<<l;
return 0;
}

Luogu P2824 排序 题解 [ 紫 ] [ 线段树 ] [ 二分 ] [ adhoc ]的更多相关文章

  1. [火星补锅] 水题大战Vol.2 T1 && luogu P1904 天际线 题解 (线段树)

    前言: 当时考场上并没有想出来...后来也是看了题解才明白 解析: 大家(除了我)都知道,奇点和偶点会成对出现,而出现的前提就是建筑的高度突然发生变化.(这个性质挺重要的,我之前没看出来) 所以就可以 ...

  2. Luogu[YNOI2019]排序(DP,线段树)

    要最优?就要一步到位,不能做"马后炮",走"回头路",因此将序列映射到一个假定最优序列,发现移动原序列等价于删除原序列元素,以便生成最大不下降子序列.可线段树维 ...

  3. Codeforces Gym 100231B Intervals 线段树+二分+贪心

    Intervals 题目连接: http://codeforces.com/gym/100231/attachments Description 给你n个区间,告诉你每个区间内都有ci个数 然后你需要 ...

  4. hdu4614 线段树+二分 插花

    Alice is so popular that she can receive many flowers everyday. She has N vases numbered from 0 to N ...

  5. 洛谷$P2824\ [HEOI2016/TJOI2016]$ 排序 线段树+二分

    正解:线段树+二分 解题报告: 传送门$QwQ$ 昂着题好神噢我$jio$得$QwQQQQQ$,,, 开始看到长得很像之前考试题的亚子,,,然后仔细康康发现不一样昂$kk$,就这里范围是$[1,n]$ ...

  6. 2021.12.09 [HEOI2016/TJOI2016]排序(线段树+二分,把一个序列转换为01串)

    2021.12.09 [HEOI2016/TJOI2016]排序(线段树+二分,把一个序列转换为01串) https://www.luogu.com.cn/problem/P2824 题意: 在 20 ...

  7. Codeforces Gym 100803G Flipping Parentheses 线段树+二分

    Flipping Parentheses 题目连接: http://codeforces.com/gym/100803/attachments Description A string consist ...

  8. 洛谷P4344 脑洞治疗仪 [SHOI2015] 线段树+二分答案/分块

    !!!一道巨恶心的数据结构题,做完当场爆炸:) 首先,如果你用位运算的时候不小心<<打成>>了,你就可以像我一样陷入疯狂的死循环改半个小时 然后,如果你改出来之后忘记把陷入死循 ...

  9. luogu4422 [COCI2017-2018#1] Deda[线段树二分]

    讨论帖:线段树二分的题..我还考场切过..白学 这题我一年前的模拟赛考场还切过,现在就不会了..好菜啊. 显然直接线段树拆成$\log n$个区间,然后每个区间在进行线段树二分即可. UPD:复杂度分 ...

  10. bzoj4399 魔法少女LJJ 线段树合并+线段树二分+并查集

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4399 题解 毒瘤题 \(9\) 种操作还有支持动态图的连通性 仔细读题 $ c<=7$. ...

随机推荐

  1. MySQL之使用pt-online-schema-change在线修改大表结构

    原因: 最近公司上一个功能, 需要为其中某个表中新增字段,但是考虑到线上数据已经达到300w+的级别,同时使用的mysql的版本是5.7而非8.0,这会导致新增字段的时候,对全表进行加锁,直到添加完毕 ...

  2. Blazor 组件库 BootstrapBlazor 中Card组件介绍

    一个较为完整的Card样子 Card组件介绍 Card组件分为三部分,CardHeader.CardBody.CardFooter. 代码格式如下: <Card> <CardHead ...

  3. Java8提供的Stream方式进行分组GroupingBy

    有时我们需要对集合进行分组操作,这时可以使用Java8提供的Stream方式进行分组.挺好用的,此处记录下.直接贴code:   Road实体: @Data @NoArgsConstructor @A ...

  4. 销讯通CRM系统如何管理医药代表的销售过程

    医药行业的销售代表与其他行业的销售代表在专业知识要求.客户群体.销售流程.以及行业特性等方面都存在明显的区别,他们必须具备更高的专业素养和综合能力. CRM(客户关系管理系统)在医药行业中对于管理医药 ...

  5. js 计算过去和未来的时间距离现在多少天

    计算传入的任意一时间.计算出这个时间距离现在还有多少天!或者计算过去的时间距离现在已经过去了多少天! 返回值有两种! 1.负值 代表过去了多少天 2.正值 代表距离设定的时间还有多少天 说明:距离设定 ...

  6. dotnet core微服务框架Jimu ~部署和调用演示

    首先运行 consul 下载 consul 以开发模式运行 consul agent -dev 2. 调试 用 Visual Studio 2022 IDE 打开项目: 右击解决方案-选择" ...

  7. 攻防世界:web习题之xff_referer

    攻防世界:web习题之xff_referer 题目内容 https://adworld.xctf.org.cn/challenges/list 这道题的网页会首先会显示: 当成功修改ip地址之后会提示 ...

  8. 使用 cProfile 分析和定位 Python 应用性能瓶颈点

    一.需求背景 性能压测时,发现某接口存在性能瓶颈,期望借助工具定位该瓶颈,最好能定位至具体慢方法. 二.cProfile 简介 cProfile 是 Python 标准库中的一个模块,用于对 Pyth ...

  9. R机器学习:朴素贝叶斯算法的理解与实操

    最近又看了很多贝叶斯算法的一些文章,好多的文章对这个算法解释起来会放一大堆公式,对代数不好的人来说真的很头疼.本文尝试着用大白话写写这个算法,再做个例子,帮助大家理解和运用. Naive Bayes ...

  10. EverEdit插件-CHM助手:一种免费、高效的CHM手册制作方式

    1 EverEdit插件-CHM助手:一种免费.高效的CHM手册制作方式 1.1 前言   业界制作CHM手册的工具多如牛毛,高贵的商业工具如:HelpNDoc.Help+Manual.HelpSmi ...