题目链接


对于序列上每一段连续区间的数我们都可以动态开点建一棵值域线段树。初始时就是\(n\)棵。

对于每次操作,我们可以将\([l,r]\)的数分别从之前它所属的若干段区间中分离出来,合并。

对于升序与降序,只需要维护一个标记,若为降序,则给左区间大的那部分。

具体实现还要用set存下每棵线段树维护的区间左端点,便于快速查找包含\([l,r]\)的区间;对每个区间维护其右端点便于快速得到区间大小。

时间、空间复杂度都是\(O((n+m)\log n)\)。

但是在洛谷上要么RE要么MLE。。其它OJ上还是能过的。


Another Solution:

对于询问二分一个值,将所有数根据与这个值的大小关系设为0/1。模拟每次操作,就是将一段区间的0/1分别放在两边。用线段树维护区间和、区间覆盖即可。最后判断是否仅p之前全是0,


线段树合并做法:

//57628kb	1692ms
#include <set>
#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 150000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=1e5+5; int n,m,R[N],root[N],tmp[N];
bool type[N];//0:↑
std::set<int> st;
char IN[MAXIN],*SS=IN,*TT=IN; struct Segment_Tree
{
#define S N*34//!
#define lson son[x][0]
#define rson son[x][1]
int tot,top,sk[S],sz[S],son[S][2]; #define Del_Node(x) sk[++top]=x
inline int New_Node()
{
int x=top?sk[top--]:++tot;
lson=rson=0, sz[x]=1;
return x;
}
void Insert(int &x,int l,int r,int p)
{
x=New_Node();
if(l==r) return;
int m=l+r>>1;
if(p<=m) Insert(lson,l,m,p);
else Insert(rson,m+1,r,p);
}
void Split(int &y,int x,int k)//将线段树分为x,y两棵,使得sz[x]==k。
{
y=New_Node();
int ls=sz[lson];
if(ls<k) Split(son[y][1],rson,k-ls);
else son[y][1]=rson, rson=0;
if(ls>k) Split(son[y][0],lson,k);
sz[y]=sz[x]-k, sz[x]=k;
}
int Merge(int x,int y)
{
if(!x||!y) return x^y;
lson=Merge(lson,son[y][0]), rson=Merge(rson,son[y][1]);
sz[x]+=sz[y], Del_Node(y); return x;
}
int Query(int x,int l,int r,int k)
{
if(l==r) return l;
int ls=sz[lson], m=l+r>>1;
if(ls>=k) return Query(lson,l,m,k);
return Query(rson,m+1,r,k-ls);
}
// void Print(int x,int l,int r)
// {
// if(!x) return;
// printf("%d:%d~%d sz:%d\n",x,l,r,sz[x]);
// if(l==r) ;
// else Print(lson,l,l+r>>1), Print(rson,(l+r>>1)+1,r);
// }
// void Output(int x){
// printf("%d root:%d type:%d:\n",x,root[x],type[x]), Print(root[x],1,n), putchar('\n');
// }
}T; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
void Split(int x,int y)//将x~y划分为一段
{
if(y<x||y>=R[x]) return;
if(!type[x]) T.Split(root[y+1],root[x],y-x+1);
else root[y+1]=root[x], T.Split(root[x],root[y+1],R[x]-y);//保留右边那部分R[x]-x+1-y+x-1
R[y+1]=R[x], R[x]=y, type[y+1]=type[x], st.insert(y+1);
}
void Merge(int x,int y)
{
if(x==y) return;//
root[x]=T.Merge(root[x],root[y]);
R[x]=R[y], st.erase(y);
}
int Query(int k)
{
std::set<int>::iterator p=st.upper_bound(k);
int x=*(--p); k-=x-1;
return type[x]?T.Query(root[x],1,n,R[x]-x+2-k):T.Query(root[x],1,n,k);
} int main()
{
n=read(), m=read();
for(int i=1; i<=n; ++i)
T.Insert(root[i],1,n,read()), st.insert(i), R[i]=i;
std::set<int>::iterator p1,p2;
for(int opt,l,r; m--; )
{
opt=read(), l=read(), r=read();
p1=st.upper_bound(l), Split(*(--p1),l-1);
p1=st.upper_bound(r), Split(*(--p1),r); p1=st.lower_bound(l), p2=st.upper_bound(r);
int now=*p1, t=0;
for(++p1; p1!=p2; ++p1) tmp[++t]=*p1;//Merge要修改set,所以还是先存下来吧。
for(int i=1; i<=t; ++i) Merge(now,tmp[i]);
type[l]=opt; //type[now]=opt;
}
printf("%d\n",Query(read())); return 0;
}

BZOJ.4552.[HEOI2016/TJOI2016]排序(线段树合并/二分 线段树)的更多相关文章

  1. [HEOI2016/TJOI2016]字符串(后缀数组+二分+主席树/后缀自动机+倍增+线段树合并)

    后缀数组解法: 先二分最长前缀长度 \(len\),然后从 \(rnk[c]\) 向左右二分 \(l\) 和 \(r\) 使 \([l,r]\) 的 \(height\geq len\),然后在主席树 ...

  2. [HEOI2016/TJOI2016] 排序 解题报告(二分答案/线段树分裂合并+set)

    题目链接: https://www.luogu.org/problemnew/show/P2824 题目描述: 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在 ...

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

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

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

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

  5. 2021.12.09 [HEOI2016/TJOI2016]排序(线段树+二分,把一个序列转换为01串)

    2021.12.09 [HEOI2016/TJOI2016]排序(线段树+二分,把一个序列转换为01串) https://www.luogu.com.cn/problem/P2824 题意: 在 20 ...

  6. 有趣的线段树模板合集(线段树,最短/长路,单调栈,线段树合并,线段树分裂,树上差分,Tarjan-LCA,势能线段树,李超线段树)

    线段树分裂 以某个键值为中点将线段树分裂成左右两部分,应该类似Treap的分裂吧(我菜不会Treap).一般应用于区间排序. 方法很简单,就是把分裂之后的两棵树的重复的\(\log\)个节点新建出来, ...

  7. BZOJ 4556 [HEOI2016/TJOI2016]字符串

    BZOJ 4556 [HEOI2016/TJOI2016]字符串 其实题解更多是用后缀数组+数据结构的做法,貌似也不好写. 反正才学了 sam 貌似比较简单的做法. 还是得先二分,然后倍增跳到 $ s ...

  8. 洛谷 P2824 [HEOI2016/TJOI2016]排序 解题报告

    P2824 [HEOI2016/TJOI2016]排序 题意: 有一个长度为\(n\)的1-n的排列\(m\)次操作 \((0,l,r)\)表示序列从\(l\)到\(r\)降序 \((1,l,r)\) ...

  9. 【线段树合并】【P2824】 [HEOI2016/TJOI2016]排序

    Description 给定一个长度为 \(n\) 的排列,有 \(m\) 次操作,每次选取一段局部进行升序或降序排序,问你一波操作后某个位置上的数字是几 Hint \(1~\leq~n,~m~\le ...

随机推荐

  1. [转]计算机视觉之跟踪算法——相关滤波器Correlation Filter

    https://blog.csdn.net/victoriaw/article/details/62416759 ASEF相关滤波器: Average of Synthetic Exact Filte ...

  2. MySQL实现强制查询走索引和强制查询不缓存

    0.表结构如下:(包含两个索引) Create Table: CREATE TABLE `user` ( `userID` ) NOT NULL, `userCode` ) DEFAULT NULL, ...

  3. Codeforces Round #504 E. Down or Right

    Codeforces Round #504 E. Down or Right 题目描述:交互题. 有一个\(n \times n\)的方阵,有一些格子是障碍,从\((1, 1)\)出发,只能向右向下走 ...

  4. 1->小规模集群架构规划

    "配置无人值守批量安装系统(Cobbler)" "搭建PPTP VPN/ NTP/Firewalld内部共享上网 " "搭建跳板机服务jumpserv ...

  5. 在jsp页面中设置了远程验证,在初始化时必须预先调用一次。

    参考链接:http://code.taobao.org/p/sztaotao/diff/5/trunk/code/src/main/webapp/webpage/modules/sys/roleFor ...

  6. linux查看内存、CPU占用资源最多的进程

    [内存占用] #利用ps命令,默认使用ps参数会显示的结果 ps -aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 ...

  7. 27 Debugging Go Code with GDB 使用GDB调试go代码

    Debugging Go Code with GDB  使用GDB调试go代码 Introduction Common Operations Go Extensions Known Issues Tu ...

  8. 使用Scrapy命令行工具【导出JSON文件】时编码设置

    Windows 10家庭中文版,Python 3.6.4,virtualenv 16.0.0,Scrapy 1.5.0, 使用scrapy命令行工具建立了爬虫项目(startproject),并使用s ...

  9. python网络编程-Select\Poll\Epoll异步IO

    首先列一下,sellect.poll.epoll三者的区别 select select最早于1983年出现在4.2BSD中,它通过一个select()系统调用来监视多个文件描述符的数组,当select ...

  10. 虚拟机 CentOS7 64

    下载地址:https://www.centos.org/download/ 下载完后以后使用虚拟机安装即可