BZOJ4552 HEOI2016/TJOI2016排序(线段树合并+线段树分裂)
很久以前写过二分答案离线的做法,比较好理解。事实上这还是一个线段树合并+分裂的板子题,相比离线做法以更优的复杂度做了更多的事情。具体不说了。怎么交了一遍luogu上就跑第一了啊
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<set>
using namespace std;
#define N 100010
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
int n,m,root[N],rev[N],cnt;
struct data{int l,r,x;
}tree[N<<];
struct data2
{
int l,r;
bool operator <(const data2&a) const
{
return r<a.r;
}
};
set<data2> q;
void ins(int &k,int x,int l,int r)
{
if (!k) k=++cnt;tree[k].x++;
if (l==r) return;
int mid=l+r>>;
if (x<=mid) ins(tree[k].l,x,l,mid);
else ins(tree[k].r,x,mid+,r);
}
void split(int &x,int &y,int rk,int op)
{
if (!x) return;
tree[y=++cnt].x=tree[x].x-rk,tree[x].x=rk;
if (op==)
{
if (tree[tree[x].l].x==rk)
{
tree[y].r=tree[x].r,tree[x].r=;
return;
}
else if (tree[tree[x].l].x>rk)
{
tree[y].r=tree[x].r,tree[x].r=;
split(tree[x].l,tree[y].l,rk,op);
}
else split(tree[x].r,tree[y].r,rk-tree[tree[x].l].x,op);
}
else
{
if (tree[tree[x].r].x==rk)
{
tree[y].l=tree[x].l,tree[x].l=;
return;
}
else if (tree[tree[x].r].x>rk)
{
tree[y].l=tree[x].l,tree[x].l=;
split(tree[x].r,tree[y].r,rk,op);
}
else split(tree[x].l,tree[y].l,rk-tree[tree[x].r].x,op);
}
}
void merge(int &x,int &y,int l,int r)
{
if (!x||!y) {x|=y;return;}
tree[x].x+=tree[y].x;
if (l<r)
{
int mid=l+r>>;
merge(tree[x].l,tree[y].l,l,mid);
merge(tree[x].r,tree[y].r,mid+,r);
}
}
int query(int k,int l,int r,int x,int op)
{
if (l==r) return l;
int mid=l+r>>;
if (op==)
{
if (tree[tree[k].l].x>=x) return query(tree[k].l,l,mid,x,op);
else return query(tree[k].r,mid+,r,x-tree[tree[k].l].x,op);
}
else
{
if (tree[tree[k].r].x>=x) return query(tree[k].r,mid+,r,x,op);
else return query(tree[k].l,l,mid,x-tree[tree[k].r].x,op);
}
}
void print(int k,int l,int r)
{
if (!tree[k].x) return;
if (l==r) {cout<<l<<' ';return;}
int mid=l+r>>;
print(tree[k].l,l,mid),print(tree[k].r,mid+,r);
}
int main()
{
n=read(),m=read();
for (int i=;i<=n;i++) ins(root[i],read(),,n),q.insert((data2){i,i});
while (m--)
{
int op=read(),l=read(),r=read();
set<data2>::iterator it=q.lower_bound((data2){l,l});
if ((*it).l<l)
{
split(root[(*it).l],root[l],l-(*it).l,rev[(*it).l]);
int L=(*it).l,R=(*it).r;
q.erase(it);
q.insert((data2){L,l-});
q.insert((data2){l,R});
rev[l]=rev[L];
}
it=q.lower_bound((data2){r+,r+});
if (it!=q.end()&&(*it).l<=r)
{
split(root[(*it).l],root[r+],r-(*it).l+,rev[(*it).l]);
int L=(*it).l,R=(*it).r;
q.erase(it);
q.insert((data2){L,r});
q.insert((data2){r+,R});
rev[r+]=rev[L];
}
it=q.lower_bound((data2){l,l});it++;
while (it!=q.end()&&(*it).r<=r) merge(root[l],root[(*it).l],,n),it++;
it=q.lower_bound((data2){l,l});
while (it!=q.end()&&(*it).r<=r) q.erase(it),it=q.lower_bound((data2){l,l});
q.insert((data2){l,r});
rev[l]=op;
//it=q.begin();while (it!=q.end()) cout<<(*it).l<<' '<<(*it).r<<" ",print(root[(*it).l],1,n),it++,cout<<endl;cout<<endl;
//it=q.begin();while (it!=q.end()) cout<<(*it).l<<' '<<(*it).r<<endl,it++;cout<<endl;
}
int x=read();
set<data2>::iterator it=q.lower_bound((data2){x,x});
cout<<query(root[(*it).l],,n,x-(*it).l+,rev[(*it).l]);
/*for (int x=1;x<=n;x++)
{
set<data2>::iterator it=q.lower_bound((data2){x,x});
cout<<query(root[(*it).l],1,n,x-(*it).l+1,rev[(*it).l])<<' ';
}*/
}
BZOJ4552 HEOI2016/TJOI2016排序(线段树合并+线段树分裂)的更多相关文章
- [HEOI2016/TJOI2016]排序 线段树+二分
[HEOI2016/TJOI2016]排序 内存限制:256 MiB 时间限制:6000 ms 标准输入输出 题目类型:传统 评测方式:文本比较 题目描述 在2016年,佳媛姐姐喜欢上了数字序列.因而 ...
- [Luogu P2824] [HEOI2016/TJOI2016]排序 (线段树+二分答案)
题面 传送门:https://www.luogu.org/problemnew/show/P2824 Solution 这题极其巧妙. 首先,如果直接做m次排序,显然会T得起飞. 注意一点:我们只需要 ...
- 2021.12.09 [HEOI2016/TJOI2016]排序(线段树+二分,把一个序列转换为01串)
2021.12.09 [HEOI2016/TJOI2016]排序(线段树+二分,把一个序列转换为01串) https://www.luogu.com.cn/problem/P2824 题意: 在 20 ...
- 2016湖南省赛 I Tree Intersection(线段树合并,树链剖分)
2016湖南省赛 I Tree Intersection(线段树合并,树链剖分) 传送门:https://ac.nowcoder.com/acm/contest/1112/I 题意: 给你一个n个结点 ...
- 洛谷 P2824 [HEOI2016/TJOI2016]排序 解题报告
P2824 [HEOI2016/TJOI2016]排序 题意: 有一个长度为\(n\)的1-n的排列\(m\)次操作 \((0,l,r)\)表示序列从\(l\)到\(r\)降序 \((1,l,r)\) ...
- 【线段树合并】【P2824】 [HEOI2016/TJOI2016]排序
Description 给定一个长度为 \(n\) 的排列,有 \(m\) 次操作,每次选取一段局部进行升序或降序排序,问你一波操作后某个位置上的数字是几 Hint \(1~\leq~n,~m~\le ...
- 洛谷 P2824 [HEOI2016/TJOI2016]排序 (线段树合并)
(另外:题解中有一种思路很高妙而且看上去可以适用一些其他情况的离线方法) 线段树合并&复杂度的简单说明:https://blog.csdn.net/zawedx/article/details ...
- BZOJ.4552.[HEOI2016/TJOI2016]排序(线段树合并/二分 线段树)
题目链接 对于序列上每一段连续区间的数我们都可以动态开点建一棵值域线段树.初始时就是\(n\)棵. 对于每次操作,我们可以将\([l,r]\)的数分别从之前它所属的若干段区间中分离出来,合并. 对于升 ...
- HDU 5649 DZY Loves Sorting(二分答案+线段树/线段树合并+线段树分割)
题意 一个 \(1\) 到 \(n\) 的全排列,\(m\) 种操作,每次将一段区间 \([l,r]\) 按升序或降序排列,求 \(m\) 次操作后的第 \(k\) 位. \(1 \leq n \le ...
随机推荐
- python读取txt文件最后一行(文件大+文件小)
txt文件小 #coding:utf-8 ''' fname为所读xx.txt文件 输出为:文件第一行和最后一行 ''' fname = 'test.txt' with open(fname, 'r' ...
- MySQL5.5.51启用网络远程连接
在其它电脑主机上访问时提示host ip is not allowed to connect to this mysql 下面代码为解决该问题的方法: :\Program Files\mysql-\b ...
- mmz-asio4delphi死链接的解决办法
最近一段时间,因为忙于网络的项目,特意到网上找了些例子,特意花时间研究了一下马敏钊写的 mmz-asio4delphi 感觉很好用,不过深入研究之后,发现一个问题. 马大的这个代码,会产生死链接. ...
- centos下Django+uwsgi+nginx
本篇章主要讲解uwsgi和nginx的作用,并利用两者对django项目进行部署 一.概述 在开发过程中,我们一般是在该项目的虚拟环境中启用django自带的web服务:python manage.p ...
- "'cl' 不是内部或外部命令,也不是可运行的程序"解决方案
最近使用VS2012+Qt5.1+QtCreator2.8.1来搭建Qt的开发环境(之前有用MinGW编译的经历,经常碰到gdb调试器崩溃的问题),全部换成想用VC的编译器和调试环境,但是觉得QtCr ...
- HybridStart发布v1.0测试版
HybridStart是一款多webview模式的混合应用前端开发框架,本来只是作者自用的一套混合应用开发模板,为了进一步提高混合应用开发效率,近期着重在框架高通用性和易用性方面做了较大改进,比如将U ...
- jquery/js记录点击事件,单击次数加一,双击清零
目的:点击按钮,点击后在网页上显示点击次数,双击清零 实现:js或者jquery 代码如下: <%@ page language="java" contentType=&qu ...
- pdf 下载demo
最近写了个pdf下载的demo,在这里记录一下.. 1 要下载pdf首先要有pdf 模板 ,制作pdf 模板就是 word 另存为 pdf . 2 用 Adobe Acrobat X Pro 这个软 ...
- web框架开发-Django简介
MVC与MTV模型 MVC Web服务器开发领域里著名的MVC模式,所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的.松耦合的方式连接在一起,模型负责业务 ...
- Nowcoder217D msc的背包 背包、生成函数、组合
传送门 发现这是一个背包问题,而\(k\)又很大,考虑生成函数方式解决这个问题. 对于体积为\(1\)的物品的生成函数为\(\frac{1}{1 - x}\),体积为\(2\)的物品的生成函数为\(\ ...