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

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. px2rem 实现vue rem 自适应/

    npm install postcss-px2rem px2rem-loader --save 新建js 文件rem.js // rem等比适配配置文件 // 基准大小 const baseSize ...

  2. sde解除锁定

    在sde数据被锁定的情况下,编辑.创建featureclass或者注册版本的时候会报告:Lock request conflicts with an established lock. 方法一:多半情 ...

  3. 【并查集+dfs】codeforces 1833 E. Round Dance

    题意 输入一个正整数 \(T(1 \leq T \leq 10^4)\),表示接下来输入 \(T\) 组测试用例,对于每一个测试用例: 第一行,输入一个正整数 \(n(2 \leq n \leq 2 ...

  4. Fake JSON Server

    Fake JSON Server https://github.com/ttu/dotnet-fake-json-server Fake JSON Server 是 Fake REST API,可以作 ...

  5. 【报错解决】【人工智能】【深度学习】验证cuda和tensorflow之间的版本对应关系时遇到的问题

    验证环境B 验证成功,没有问题 验证环境A 得到结果false 检查是否与CUDA关联成功 tf.test.is_built_with_cuda() 发现没有关联成功 根据查询可知道,失败的原因是1. ...

  6. virtualbox设置了共享文件夹却无权限访问

    在virtualbox中设置共享文件夹后,然后登陆ubuntu系统访问共享文件夹,发现没有权限.查看共享文件夹的属性可知,共享文件夹的所有者是root,所属的组是vboxsf.以用户登录的时候,自然是 ...

  7. betterZip解压后压缩包会删除 zip文件解压后原压缩文件能不能删掉

    https://www.betterzipcn.com/faq/better-ydeq.html 品牌型号:MacBook Book Air 系统:MacOS Mojave 10.14 软件版本:Be ...

  8. Windows交叉编译MNN-3.0.0安卓版本库

    一.写在前面 以下的步骤.流程都是基于MNN的文档,再结合自己的实践得出的,仅作为参考. 博主的环境是windows10专业版 MNN文档 MNN的Github仓库地址 二.下载MNN-3.0.0主库 ...

  9. Qt音视频开发03-ffmpeg倍速播放(半倍速/2倍速/4倍速/8倍速)

    一.前言 用ffmpeg做倍速播放,是好多年都一直没有实现的功能,有个做法是根据倍速参数,不断切换播放位置,实现效果不是很好,ffplay中的倍速就做得很好,而且声音无论倍速多少还非常柔和,有特别的降 ...

  10. vue 路由警告 Duplicate named routes definition

    今天在开发的时候,项目报了一个警告  Duplicate named routes definition ,这里记录一下解决方式和思路. 警告产生的原因根据提示内容,我们大概猜测是和路由的name有关 ...