排序HEOI2016/TJOI2016 二分+线段树判定
LINK:排序 此题甚好我一点思路都没有要是我当时省选此题除了模拟我恐怕想不到还可以二分 还可以线段树。。。
有点ex 不太好写 考虑 暴力显然每次给出询问我们都是可以直接sort的 无视地形无视一切直接sort 。复杂度mnlogn 30分到手。
考虑更为优秀的做法 桶排序 每次排序都是O(n)总体复杂度 nm 50分到手
考虑 不模拟做题 不断排序肯定是行不通的 如何 改变问题模型是关键之处。
然鹅 很难想到解法 思路引导一下 0 1 序列线段树树是很容易支持排序的 区间修改区间查询即可。再考虑答案是否具有单调性 从数值大小来说答案虽然是确定的 但是 显然也具有单调性(虽然有点牵强
但是我们可以不断地缩小答案的 取值范围 从而寻找到答案这是关键,从答案的值域角度来说的确可以二分。想办法不断缩小答案的值域,怎么办?
考虑最终拍好序的队列>=mid 为1 反之为0 那么我们把整个操作倒序的实现其实就是0 1 的不断排序。且最后询问的位置一定为1。因为>=当前答案。
考虑如果答案较大那么经过0 1 的排序之后最后询问的位置一定不为1 所以我们成功的缩小的值域 从而达到判定mid的效果二分可行 排序01串用上述方法搞就好了。
写完了 码力最近下降很多 可能 打代码的时候 精力不够吧。
//#include<bits/stdc++.h>
#include<iostream>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<cctype>
#include<utility>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<deque>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<iomanip>
#include<stack>
#include<string>
#include<cstring>
#define INF 1000000000
#define ll long long
#define db double
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define sum(x) t[x].sum
#define cnt(x) t[x].cnt
#define l(x) t[x].l
#define r(x) t[x].r
#define tag(x) t[x].tag
#define op(i) s[i].op
#define x(i) s[i].x
#define y(i) s[i].y
#define zz p<<1
#define yy p<<1|1
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
const int MAXN=;
int n,m,pos,sum0,sum1;
int a[MAXN],b[MAXN];
struct wy
{
int l,r;
int sum,cnt;
int tag;
}t[MAXN<<];
struct data{int op,x,y;}s[MAXN];
inline void build(int p,int l,int r)
{
l(p)=l;r(p)=r;tag(p)=-;
if(l==r){sum(p)=b[l];cnt(p)=b[l]^;return;}
int mid=(l+r)>>;
build(zz,l,mid);
build(yy,mid+,r);
sum(p)=sum(zz)+sum(yy);
cnt(p)=cnt(zz)+cnt(yy);
}
inline void pushdown(int p)
{
int mid=(l(p)+r(p))>>;
if(tag(p)==)
{
sum(zz)=(mid-l(p)+);
cnt(zz)=;
sum(yy)=r(p)-mid;
cnt(yy)=;
tag(zz)=tag(yy)=;
tag(p)=-;return;
}
sum(zz)=;
cnt(zz)=(mid-l(p)+);
sum(yy)=;
cnt(yy)=r(p)-mid;
tag(yy)=tag(zz)=;
tag(p)=-;return;
}
inline void change(int p,int l,int r,int x)
{
if(l>r)return;
if(l<=l(p)&&r>=r(p))
{
if(x==)
{
sum(p)=r(p)-l(p)+;
cnt(p)=;tag(p)=;
return;
}
cnt(p)=r(p)-l(p)+;
sum(p)=;tag(p)=;
return;
}
if(tag(p)!=-)pushdown(p);
int mid=(l(p)+r(p))>>;
if(l<=mid)change(zz,l,r,x);
if(r>mid)change(yy,l,r,x);
sum(p)=sum(zz)+sum(yy);
cnt(p)=cnt(zz)+cnt(yy);
}
inline void ask(int p,int l,int r)
{
if(l<=l(p)&&r>=r(p))
{
sum0+=cnt(p);
sum1+=sum(p);
return;
}
if(tag(p)!=-)pushdown(p);
int mid=(l(p)+r(p))>>;
if(l<=mid)ask(zz,l,r);
if(r>mid)ask(yy,l,r);
return;
}
inline int check(int x)
{
for(int i=;i<=n;++i)b[i]=a[i]>=x?:;
build(,,n);
for(int i=;i<=m;++i)
{
sum0=sum1=;
ask(,x(i),y(i));
if(!op(i))//0升序
{
//cout<<x(i)<<' '<<x(i)+sum0-1<<endl;
//cout<<x(i)+sum0<<' '<<y(i)<<endl;
change(,x(i),x(i)+sum0-,);
change(,x(i)+sum0,y(i),);
}
else
{
change(,x(i),x(i)+sum1-,);
change(,x(i)+sum1,y(i),);
}
}
sum0=sum1=;
ask(,pos,pos);
return sum1;
}
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();
for(int i=;i<=n;++i)a[i]=read();
for(int i=;i<=m;++i)
{
int op,x,y;
op=read();x=read();y=read();
s[i]=(data){op,x,y};
}
pos=read();
int l=,r=n;
while(l+<r)
{
int mid=(l+r)>>;
if(check(mid))l=mid;
else r=mid;
}
if(check(r))printf("%d\n",r);
else printf("%d\n",l);
return ;
}
最后再次回顾本题这样做法的正确性 1 我们似乎找不到一种除了模拟之外更好的方法解决本题
2 强行考虑答案的单调性 发现答案的值域显然具有单调性 想办法缩小值域 直至找到答案。
3 缩小值域方法的正确性 对于>=答案的数字看成1的话反之为0 考虑最终的序列我们可以将其抽象成0 1 串那么最后答案所在位为1。每次排序的时候我们都是将1排到前面或排到后面 最终形成一个最终的序列,于是乎我们利用等效法确定了一个01串只要这个01串最后的排序满足答案的位置为1 那么当前mid就有可能合法然后二分不断地去找那个成功与不成功的边界成功的边界就是我们寻找的答案了,正确性可以理解为等效法显然是正确的 判断的正确性显然是单调(答案可以做到比答案小的也就是1的数量更多也能做到。故此方法正确。于是就成功的解决了这个看似解决不了的问题。
排序HEOI2016/TJOI2016 二分+线段树判定的更多相关文章
- BZOJ4552 [Tjoi2016&Heoi2016]排序 【二分 + 线段树】
题目链接 BZOJ4552 题解 之前去雅礼培训做过一道题,\(O(nlogn)\)维护区间排序并能在线查询 可惜我至今不能get 但这道题有着\(O(nlog^2n)\)的离线算法 我们看到询问只有 ...
- BZOJ4552(二分+线段树)
要点 序列是n个不同的数,则新学到的一种策略就是二分这个位置的答案,然后可以上下调. 神奇地只关注大于还是小于mid并赋值0.1,这样m个操作的排序就能用线段树维护了! #include <cs ...
- HDU4614 Vases and Flowers 二分+线段树
分析:感觉一看就是二分+线段树,没啥好想的,唯一注意,当开始摆花时,注意和最多能放的比大小 #include<iostream> #include<cmath> #includ ...
- J - Joseph and Tests Gym - 102020J (二分+线段树)
题目链接:https://cn.vjudge.net/contest/283920#problem/J 题目大意:首先给你n个门的高度,然后q次询问,每一次询问包括两种操作,第一种操作是将当前的门的高 ...
- Educational Codeforces Round 61 D 二分 + 线段树
https://codeforces.com/contest/1132/problem/D 二分 + 线段树(弃用结构体型线段树) 题意 有n台电脑,只有一个充电器,每台电脑一开始有a[i]电量,每秒 ...
- 【BZOJ-3110】K大数查询 整体二分 + 线段树
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6265 Solved: 2060[Submit][Sta ...
- hdu6070 Dirt Ratio 二分+线段树
/** 题目:hdu6070 Dirt Ratio 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6070 题意:给定n个数,求1.0*x/y最小是多少.x ...
- K-th occurrence HDU - 6704 (后缀数组+二分线段树+主席树)
大意: 给定串s, q个询问(l,r,k), 求子串s[l,r]的第kk次出现位置. 这是一篇很好的题解: https://blog.csdn.net/sdauguanweihong/article/ ...
- 【BZOJ4552】[Tjoi2016&Heoi2016]排序 二分+线段树
[BZOJ4552][Tjoi2016&Heoi2016]排序 Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题 ...
随机推荐
- CountDownLatch 线程工具类
CountDownLatch:概念是,允许一个或多个线程等待其他线程完成操作: 在线程基础知识中,学习过线程的join方法,当前线程阻塞等待join线程执行完毕才能执行: 测试代码如下: public ...
- 6.29模拟赛 (T1:李时珍的皮肤衣 T2:马大嘴的废话 T3:SSY的队列 T4:清理牛棚);
啊,又是考炸的一天,成功的退步了三名,啊,成共的看错了T1 的题意 ,水了80分. 第十五名就是我,额,已经有点倒数的感觉了,并且一道题都没AC 我太难了. 好了,废话不多说了,下面正式提接: 这 ...
- Django---进阶9
目录 自定义分页器的拷贝及使用 Forms组件 前戏 基本使用 校验数据 渲染标签 展示提示信息 钩子函数(HOOK) forms组件其他参数及补充知识点 作业 自定义分页器的拷贝及使用 " ...
- 动手实现一个简单的 rpc 框架到入门 grpc (上)
rpc 全称 Remote Procedure Call 远程过程调用,即调用远程方法.我们调用当前进程中的方法时很简单,但是想要调用不同进程,甚至不同主机.不同语言中的方法时就需要借助 rpc 来实 ...
- postman 进阶技巧
cookie 清除缓存 code 生成接口自动化测试脚本 响应部分 pretty 响应以json或xml显示 raw 响应以文本显示 preview 以HTML网页行驶显示 断言 断言:用于判断接口请 ...
- 《SpringBoot判空处理》接开@valid的面纱
一.事有起因 我们在与前端交互的时候,一般会遇到字段格式校验及非空非null的校验,在没有SpringBoot注解的时候, 我们可能会在service进行处理: if(null == name){ t ...
- MySQL入门(引擎、数据类型、约束)
MySQL入门(二) 表的引擎:驱动数据的方式 - 数据库优化 # 概要:引擎是建表规定的,提供给表使用,不是数据库的 # 展示所有引擎 show engines; # innodb(默认): 支持事 ...
- HTML5提高
HTML5提高 前言 我个人觉得,当你学会了一些最基本的标签其实是够用的,但是在很多网页中可以发现很多新的标签.这个时候不知道它是干嘛的实际上心里是非常没底的,所以在这里我打算写一篇HTML5提高的文 ...
- scala 数据结构(五):队列 Queue
1 队列 Queue-基本介绍 队列的说明 1)队列是一个有序列表,在底层可以用数组或是链表来实现. 2)其输入和输出要遵循先入先出的原则.即:先存入队列的数据,要先取出.后存入的要后取出 3)在Sc ...
- vue 写h5页面-摇一摇
依赖的第三方的插件 shake.js github地址: https://github.com/alexgibson/shake.js 提供一个摇一摇音效下载地址:http://aspx.sc.chi ...