题面

传送门

分析

此题是道好题!

首先要跳出思维定势,不是去想如何用数据结构去直接维护排序过程,而是尝试二分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);
}

BZOJ 4552(二分+线段树+思维)的更多相关文章

  1. HDU4614 Vases and Flowers 二分+线段树

    分析:感觉一看就是二分+线段树,没啥好想的,唯一注意,当开始摆花时,注意和最多能放的比大小 #include<iostream> #include<cmath> #includ ...

  2. BZOJ.4184.shallot(线段树分治 线性基)

    BZOJ 裸的线段树分治+线性基,就是跑的巨慢_(:з」∠)_ . 不知道他们都写的什么=-= //41652kb 11920ms #include <map> #include < ...

  3. J - Joseph and Tests Gym - 102020J (二分+线段树)

    题目链接:https://cn.vjudge.net/contest/283920#problem/J 题目大意:首先给你n个门的高度,然后q次询问,每一次询问包括两种操作,第一种操作是将当前的门的高 ...

  4. Educational Codeforces Round 61 D 二分 + 线段树

    https://codeforces.com/contest/1132/problem/D 二分 + 线段树(弃用结构体型线段树) 题意 有n台电脑,只有一个充电器,每台电脑一开始有a[i]电量,每秒 ...

  5. 【BZOJ-3110】K大数查询 整体二分 + 线段树

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6265  Solved: 2060[Submit][Sta ...

  6. hdu6070 Dirt Ratio 二分+线段树

    /** 题目:hdu6070 Dirt Ratio 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6070 题意:给定n个数,求1.0*x/y最小是多少.x ...

  7. [BZOJ 4025]二分图(线段树分治+带边权并查集)

    [BZOJ 4025]二分图(线段树分治+带边权并查集) 题面 给出一个n个点m条边的图,每条边会在时间s到t出现,问每个时间的图是否为一个二分图 \(n,m,\max(t_i) \leq 10^5\ ...

  8. K-th occurrence HDU - 6704 (后缀数组+二分线段树+主席树)

    大意: 给定串s, q个询问(l,r,k), 求子串s[l,r]的第kk次出现位置. 这是一篇很好的题解: https://blog.csdn.net/sdauguanweihong/article/ ...

  9. BZOJ.4552.[HEOI2016/TJOI2016]排序(线段树合并/二分 线段树)

    题目链接 对于序列上每一段连续区间的数我们都可以动态开点建一棵值域线段树.初始时就是\(n\)棵. 对于每次操作,我们可以将\([l,r]\)的数分别从之前它所属的若干段区间中分离出来,合并. 对于升 ...

随机推荐

  1. 关于js节流函数throttle和防抖动debounce

    废话不多说,直奔主题. 什么是throttle和debounce? 这两个方法的主要目的多是用于性能优化.最常见的应用尝尽就是在通过监听resize.scroll.mouseover等事件时候的性能消 ...

  2. maven 坐标获取方式

    问题:我们在开发时pom.xml文件中的 <dependencies>     <dependency>         <groupId>org.mybatis& ...

  3. Python---协程---重写多进程

    一. # 匹配一行文字中所有开头的字母import re s = 'i love you but you don\'t love me' # \b\m findallcontent = re.find ...

  4. linux运维、架构之路-MySQL日志(三)

    一.MySQL日志 1.错误日志 ①配置方法 [mysqld] log-error=/data/mysql/mysql.log ②查看配置方式 mysql> show variables lik ...

  5. extjs计算两个DateField所间隔的月份(天数)

    需求:两个DateField控件,分别为开始时间和结束时间.当选择完结束时间后,自动计算这两个时间段所间隔的月或天数. 需要解决的问题: 1.直接使用Ext.getCmp('endDate').get ...

  6. 【学习心得】Link-cut Tree

    Link-cut Tree是一种支持改变树(森林)的形态(link和cut),同时维护树的路径上节点信息的数据结构.lct通过splay来维护每次的perferred path,说白了就是一个动态的树 ...

  7. 【bzoj1588】[HNOI2002]营业额统计

    题目描述: 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额. ...

  8. 3D Computer Grapihcs Using OpenGL - 07 Passing Data from Vertex to Fragment Shader

    上节的最后我们实现了两个绿色的三角形,而绿色是直接在Fragment Shader中指定的. 这节我们将为这两个三角形进行更加自由的着色——五个顶点各自使用不同的颜色. 要实现这个目的,我们分两步进行 ...

  9. HDU 6438 Buy and Resell

    高卖低买,可以交易多次 维护一个优先队列,贪心 相当于每天卖出 用当前元素减优先队列最小得到收益 用0/卖出,1/买入标志是否真实进行了交易,记录次数 #include<bits/stdc++. ...

  10. Java 统计单词频数

    输出单个文件中的 N 个英语单词出现的次数 定义双列集合,将单词不重复的读入一列中,另一列用来计数 import java.io.BufferedReader; import java.util.Ar ...