题意

所谓线段树分裂其实是本题的在线做法。

考虑如果我们有一个已经排好序的区间的权值线段树,那么就可以通过线段树上二分的方法得到第\(k\)个数是谁。

于是用set维护每个升序/降序区间的左右端点以及对应的线段树根节点,区间排序就将区间拆出来,并将对应的线段树也拆出来。

拆线段树就是将前k个值建一棵新树拆出来,用类似fhq treap的方法即可。

code:

#include<bits/stdc++.h>
using namespace std;
#define lc(p) (seg[p].lc)
#define rc(p) (seg[p].rc)
#define sum(p) (seg[p].sum)
const int maxn=1e5+10;
int n,m,Q,tot;
int a[maxn];
queue<int>pool;
struct Seg{int lc,rc,sum;}seg[maxn*20];
struct node
{
int l,r,root,op;
bool operator<(const node& x)const{return r==x.r?l<x.l:r<x.r;}
};
set<node>s;
inline int read()
{
char c=getchar();int res=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
return res*f;
}
inline int New()
{
int x;
if(!pool.empty())x=pool.front(),pool.pop();
else x=++tot;
lc(x)=rc(x)=sum(x)=0;
return x;
}
void insert(int &p,int l,int r,int pos)
{
if(!p)p=New();
sum(p)++;
if(l==r)return;
int mid=(l+r)>>1;
if(pos<=mid)insert(lc(p),l,mid,pos);
else insert(rc(p),mid+1,r,pos);
}
void split(int &p,int q,int l,int r,int k)
{
if(!k)return;
if(!p)p=New();
sum(p)+=k,sum(q)-=k;
if(l==r)return;
int mid=(l+r)>>1,tmp=sum(lc(q));
if(k<tmp)split(lc(p),lc(q),l,mid,k);
else
{
lc(p)=lc(q),lc(q)=0;
split(rc(p),rc(q),mid+1,r,k-tmp);
}
}
int merge(int p,int q)
{
if(!p||!q)return p+q;
lc(p)=merge(lc(p),lc(q));rc(p)=merge(rc(p),rc(q));
sum(p)+=sum(q);
pool.push(q);
return p;
}
int find(int p,int l,int r,int k)
{
if(l==r)return l;
int mid=(l+r)>>1;
if(sum(lc(p))>=k)return find(lc(p),l,mid,k);
else return find(rc(p),mid+1,r,k-sum(lc(p)));
}
inline int nodesplit(int l,int r)
{
set<node>::iterator it=s.lower_bound((node){0,l,0,0});
if((it->l)!=l)
{
node now=*it;
int p=0;
s.erase(it);
if(!now.op)
{
split(p,now.root,1,n,l-now.l);
s.insert((node){now.l,l-1,p,0});
s.insert((node){l,now.r,now.root,0}); }
else
{
split(p,now.root,1,n,now.r-l+1);
s.insert((node){now.l,l-1,now.root,1});
s.insert((node){l,now.r,p,1});
}
}
it=s.lower_bound((node){0,r,0,0});
if((it->r)!=r)
{
node now=*it;
int p=0;
s.erase(it);
if(!now.op)
{
split(p,now.root,1,n,r-now.l+1);
s.insert((node){now.l,r,p,0});
s.insert((node){r+1,now.r,now.root,0});
}
else
{
split(p,now.root,1,n,now.r-r);
s.insert((node){now.l,r,now.root,1});
s.insert((node){r+1,now.r,p,1});
}
}
int p=0;
while(2333)
{
it=s.lower_bound((node){0,l,0,0});
if(it==s.end()||(it->l)>r)break;
node now=*it;s.erase(it);
p=merge(p,now.root);
}
return p;
}
int main()
{
//freopen("test.in","r",stdin);
//freopen("test.out","w",stdout);
n=read(),m=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=n;i++)
{
int p=0;
insert(p,1,n,a[i]);s.insert((node){i,i,p,0});
}
for(int i=1;i<=m;i++)
{
int op=read(),l=read(),r=read(),p;
p=nodesplit(l,r);
s.insert((node){l,r,p,op});
}
Q=read();
int p=nodesplit(Q,Q);
printf("%d",find(p,1,n,1));
return 0;
}

luoguP2824 [HEOI2016/TJOI2016]排序(线段树分裂做法)的更多相关文章

  1. [HEOI2016/TJOI2016]排序 线段树+二分

    [HEOI2016/TJOI2016]排序 内存限制:256 MiB 时间限制:6000 ms 标准输入输出 题目类型:传统 评测方式:文本比较 题目描述 在2016年,佳媛姐姐喜欢上了数字序列.因而 ...

  2. [Luogu P2824] [HEOI2016/TJOI2016]排序 (线段树+二分答案)

    题面 传送门:https://www.luogu.org/problemnew/show/P2824 Solution 这题极其巧妙. 首先,如果直接做m次排序,显然会T得起飞. 注意一点:我们只需要 ...

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

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

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

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

  5. Luogu P2824 [HEOI2016/TJOI2016]排序 线段树+脑子

    只会两个$log$的$qwq$ 我们二分答案:设答案为$ans$,则我们把$a[i]<=ans$全部设成$0$,把$a[i]>ans$全部设成$1$,扔到线段树里,这样区间排序(升序)就是 ...

  6. day 1 晚上 P2824 [HEOI2016/TJOI2016]排序 线段树

    #include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #inclu ...

  7. 排序HEOI2016/TJOI2016 二分+线段树判定

    LINK:排序 此题甚好我一点思路都没有要是我当时省选此题除了模拟我恐怕想不到还可以二分 还可以线段树... 有点ex 不太好写 考虑 暴力显然每次给出询问我们都是可以直接sort的 无视地形无视一切 ...

  8. luoguP2824 [HEOI2016/TJOI2016]排序(二分答案做法)

    题意 这题的思路实在巧妙. 首先我们肯定无法对区间进行sort,那么考虑如何使得sort简化. 问:如果给的序列是一个0-1序列,让你区间排序,那么怎么做? 答:建一颗线段树维护sum,求出当前区间中 ...

  9. BZOJ4552 HEOI/TJOI2016 排序 线段树、二分答案

    题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=4552 题意:给出一个$1$到$N$的全排列,对其进行$M$次排序,每次排序将区间$[l ...

随机推荐

  1. 201871010116-祁英红《面向对象程序设计(java)》第十一周学习总结

    博文正文开头格式:(2分) 项目 内容 <面向对象程序设计(java)> https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://ww ...

  2. Re-stheasy

    https://dn.jarvisoj.com/challengefiles/ctf2.b93676be23733b2fcda3988c1133c1c1 用IDA-32bit 打开,找到main函数 ...

  3. Deepin 15.9系统直接运行exe运行程序

    以下为你介绍在深度Deepin 15.9 Linux操作系统下直接运行exe文件的方法,此方法基于deepin-wine实现,经测试,一些exe文件是可以正常打开的,但部分可能会出现无法使用的情况,但 ...

  4. Flink JobManager 和 TaskManager 原理

    转自:https://www.cnblogs.com/nicekk/p/11561836.html 一.概述 Flink 整个系统主要由两个组件组成,分别为 JobManager 和 TaskMana ...

  5. Bootstrap --------- 了解与使用

    Bootstrap是用来做什么的?有几大部分?谁开发的?有什么特点? 一个用于快速开发 Web 应用程序和网站的前端框架. 基于 HTML.CSS.JAVASCRIPT 的. 2011 年八月在 Gi ...

  6. 内核态发生非法地址访问是否会panic

    https://mp.weixin.qq.com/s?__biz=MzAwMDUwNDgxOA==&mid=2652663676&idx=1&sn=b18ab57322594e ...

  7. jQuery 源码分析(十七) 事件系统模块 实例方法和便捷方法 详解

    实例方法和便捷方法是指jQuery可以直接通过链接操作的方法,是通过调用$.event上的方法(上一节介绍的底层方法)来实现的,常用的如下: on(types,selector,data,fn,one ...

  8. [转]在.NET Core 2.x中将多个强类型设置实例与命名选项一起使用

    自1.0版之前,ASP.NET Core已使用“ 选项”模式配置强类型设置对象.从那时起,该功能获得了更多功能.例如,引入了ASP.NET Core 1.1 IOptionsSnapshot,它允许您 ...

  9. 新增SAP到OA接口,OA怎么更新WSDL给PI,怎么选择PI的IP地址(备忘)

    1.首先定义个class. 弄完以后可以使用http://IP地址:8088/seeyon/services/sapService?wsdl  进行导出,部署在哪个服务器就用哪个服务器的IP地址 pr ...

  10. Java生鲜电商平台-Java后端生成Token架构与设计详解

    Java生鲜电商平台-Java后端生成Token架构与设计详解 目的:Java开源生鲜电商平台-Java后端生成Token目的是为了用于校验客户端,防止重复提交. 技术选型:用开源的JWT架构. 1. ...