题意

一个 \(1\) 到 \(n\) 的全排列,\(m\) 种操作,每次将一段区间 \([l,r]\) 按升序或降序排列,求 \(m\) 次操作后的第 \(k\) 位。

\(1 \leq n \leq 10^5\)

思路

两个 \(\log\) 的做法展现了二分答案的强大功能。首先二分枚举第 \(k\) 位的值,然后将小于等于它的数都变为 \(1\) ,大于它的数变为 \(0\) ,线段树可以实现对 \(01\) 序列快速的排序,按要求进行排序,然后如果第 \(k\) 位为 \(1\) 说明这个数小于等于 \(k\) ,就这样不断二分下来,得到的边界值就是第 \(k\) 位真实的值。这个做法是离线的,有两个 \(\log\) ,但代码好实现。

但这道题,有一个 \(\log\) 、在线的做法。考虑每个位置开一棵动点线段树,把这个位置的数扔进线段树,区间的排序直接用线段树合并进行,但是如果区间的某个端点落在某一个完整的区间内,那就会破坏这个区间的单调性,所以还要线段树分割。我们对于一个完整区间,存下是升序还是降序,然后“分割”出需要的元素,线段树分割代码如下:

void split(int &x,int y,int K,int l,int r)		//y拆前K个给x,合并前将初始x清零(x是一个空树)
{
create(x);
if(l==r){sum[x]=sum[y],sum[y]=0;return;}
int mid=(l+r)>>1;
if(K<=sum[lson[y]])
{
split(lson[x],lson[y],K,l,mid);
sum[x]=sum[lson[x]]+sum[rson[x]];
sum[y]=sum[lson[y]]+sum[rson[y]];
return;
}
split(rson[x],rson[y],K-sum[lson[y]],mid+1,r);
lson[x]=lson[y],lson[y]=0;
sum[x]=sum[lson[x]]+sum[rson[x]];
sum[y]=sum[lson[y]]+sum[rson[y]];
}

和线段树合并的写法大致相同。

初始有 \(n\log n\) 个点,每次操作最多分割出 \(2\log n\) 个节点 ,所以空间复杂度为 \(O(n\log n)\)。

合并初始的 \(n\) 个节点有一个 \(n\log n\) ,而分割的节点也最多是 \(2 n\log n\) ,所以时间复杂度也是 \(O(n\log n)\)。

代码

#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
typedef long long LL;
using namespace std;
const int N=1e5+5;
const int NN=N*60;
bool mmr1;
int sum[NN],lson[NN],rson[NN];
int rt[N],tot;
void build()
{
memset(rt,0,sizeof(rt));
sum[tot=0]=lson[0]=rson[0]=0;
}
void create(int &k){if(!k)k=++tot,sum[k]=lson[k]=rson[k]=0;}
void update(int &k,int x,int l,int r)
{
create(k);
sum[k]++;
if(l==r)return;
int mid=(l+r)>>1;
if(x<=mid)update(lson[k],x,l,mid);
else update(rson[k],x,mid+1,r);
}
int query1(int k,int K,int l,int r)
{
if(l==r)
{
if(sum[k]!=1)return -1;
return l;
}
int mid=(l+r)>>1;
if(K<=sum[lson[k]])return query1(lson[k],K,l,mid);
else return query1(rson[k],K-sum[lson[k]],mid+1,r);
}
int query2(int k,int K,int l,int r)
{
if(l==r)
{
if(sum[k]!=1)return -1;
return l;
}
int mid=(l+r)>>1;
if(K<=sum[rson[k]])return query2(rson[k],K,mid+1,r);
else return query2(lson[k],K-sum[rson[k]],l,mid);
}
void merge(int &x,int y,int l,int r) //y并进x
{
if(!x||!y){x=(x|y);return;}
if(l==r){sum[x]+=sum[y];return;}
int mid=(l+r)>>1;
merge(lson[x],lson[y],l,mid);
merge(rson[x],rson[y],mid+1,r);
sum[x]=sum[lson[x]]+sum[rson[x]];
}
void split1(int &x,int y,int K,int l,int r) //y拆前K个给x
{
create(x);
if(l==r){sum[x]=sum[y],sum[y]=0;return;}
int mid=(l+r)>>1;
if(K<=sum[lson[y]])
{
split1(lson[x],lson[y],K,l,mid);
sum[x]=sum[lson[x]]+sum[rson[x]];
sum[y]=sum[lson[y]]+sum[rson[y]];
return;
}
split1(rson[x],rson[y],K-sum[lson[y]],mid+1,r);
lson[x]=lson[y],lson[y]=0;
sum[x]=sum[lson[x]]+sum[rson[x]];
sum[y]=sum[lson[y]]+sum[rson[y]];
}
void split2(int &x,int y,int K,int l,int r) //y拆后K个给x
{
create(x);
if(l==r){sum[x]=sum[y],sum[y]=0;return;}
int mid=(l+r)>>1;
if(K<=sum[rson[y]])
{
split2(rson[x],rson[y],K,mid+1,r);
sum[x]=sum[lson[x]]+sum[rson[x]];
sum[y]=sum[lson[y]]+sum[rson[y]];
return;
}
split2(lson[x],lson[y],K-sum[rson[y]],l,mid);
rson[x]=rson[y],rson[y]=0;
sum[x]=sum[lson[x]]+sum[rson[x]];
sum[y]=sum[lson[y]]+sum[rson[y]];
}
set<int>st;
set<int>::iterator it,it1;
bool f[N]; int find_leftmost(int x)
{
it=st.upper_bound(x);
return *--it;
}
int find_rightmost(int x)
{
it=st.upper_bound(x);
return (*it)-1;
}
bool mmr2; int main()
{
int T,n,m,K;
scanf("%d",&T);
while(T--)
{
build();
st.clear();
memset(f,0,sizeof(f));
scanf("%d%d",&n,&m);
FOR(i,1,n)
{
int x;
scanf("%d",&x);
update(rt[i],x,1,n);
}
FOR(i,1,n+1)st.insert(i); while(m--)
{
int op,l,r;
scanf("%d%d%d",&op,&l,&r);
int L=find_leftmost(l);
if(l!=L)
{
if(f[L]==0)rt[l]=0,split1(rt[l],rt[L],l-L,1,n);
else rt[l]=0,split2(rt[l],rt[L],l-L,1,n);
swap(rt[l],rt[L]);
f[l]=f[L];
st.insert(l);
} int R=find_rightmost(r),_R=find_leftmost(r);
if(r!=R)
{
f[r+1]=f[_R];
if(f[_R]==0)rt[r+1]=0,split2(rt[r+1],rt[_R],R-r,1,n);
else rt[r+1]=0,split1(rt[r+1],rt[_R],R-r,1,n);
st.insert(r+1);
} f[l]=op;
it=st.find(l),it++;
while((*it)<=r)
{
merge(rt[l],rt[*it],1,n);
it1=it,it++,st.erase(it1);
}
}
scanf("%d",&K);
int x=find_leftmost(K);
if(f[x]==0)printf("%d\n",query1(rt[x],K-x+1,1,n));
else printf("%d\n",query2(rt[x],K-x+1,1,n));
}
return 0;
}

HDU 5649 DZY Loves Sorting(二分答案+线段树/线段树合并+线段树分割)的更多相关文章

  1. hdu 5649 DZY Loves Sorting 二分+线段树

    题目链接 给一个序列, 两种操作, 一种是将[l, r]里所有数升序排列, 一种是降序排列. 所有操作完了之后, 问你a[k]等于多少. 真心是涨见识了这题..好厉害. 因为最后只询问一个位置, 所以 ...

  2. 数据结构(线段树):HDU 5649 DZY Loves Sorting

    DZY Loves Sorting Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Oth ...

  3. HDU 5649.DZY Loves Sorting-线段树+二分-当前第k个位置的数

    DZY Loves Sorting Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Oth ...

  4. hdu 5646 DZY Loves Partition 二分+数学分析+递推

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=5646 题意:将n分成k个正整数之和,要求k个数全部相同:并且这k个数的乘积最大为多少?结果mod 1e^9 ...

  5. BZOJ_3316_JC loves Mkk_ 二分答案 + 单调队列

    BZOJ_3316_JC loves Mkk_ 二分答案 + 单调队列 题意: 分析: 拆成链,二分答案,奇偶两个单调队列维护最大子段和,记录方案. 代码: #include <cstdio&g ...

  6. hdu 5195 DZY Loves Topological Sorting 线段树+拓扑排序

    DZY Loves Topological Sorting Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/sho ...

  7. hdu 5195 DZY Loves Topological Sorting BestCoder Round #35 1002 [ 拓扑排序 + 优先队列 || 线段树 ]

    传送门 DZY Loves Topological Sorting Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131 ...

  8. hdu 5195 DZY Loves Topological Sorting (拓扑排序+线段树)

    DZY Loves Topological Sorting Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 ...

  9. HDU 5646 DZY Loves Partition 数学 二分

    DZY Loves Partition 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5646 Description DZY loves parti ...

随机推荐

  1. flask模板的基本用法(定界符、模板语法、渲染模板),模板辅助工具(上下文、全局对象、过滤器、测试器、模板环境对象)

    flask模板 在动态web程序中,视图函数返回的HTML数据往往需要根据相应的变量(比如查询参数)动态生成. 当HTML代码保存到单独的文件中时,我们没法再使用字符串格式化或拼接字符串的当时在HTM ...

  2. HADOOP nutch java mysql

    下载Hadoop安装包 wget  http://apache.fayea.com/hadoop/common/hadoop-2.7.2/hadoop-2.7.2.tar.gz   java安装 wg ...

  3. Win10+Ubuntu16.04双系统安装过程中遇到的一些问题及解决办法

    前两天闲来无聊重装了系统,装的是win10 64的系统,后来心血来潮索性再装Ubuntu,搞成win10+Ubuntu双系统. win10系统的镜像文件可以通过MSDN网站获取,MSDN是一个很可靠的 ...

  4. flask框架----flask中的wtforms使用

    一.简单介绍flask中的wtforms WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证. 安装: pip3 install wtforms 二.简单使用wtfo ...

  5. ltp-ddt的makefile结构

    顶层makefile COMMON_TARGETS        := pan utils COMMON_TARGETS    += tools testcases/ddt COMMON_TARGET ...

  6. Scrapy框架学习 - 使用内置的ImagesPipeline下载图片

    需求分析需求:爬取斗鱼主播图片,并下载到本地 思路: 使用Fiddler抓包工具,抓取斗鱼手机APP中的接口使用Scrapy框架的ImagesPipeline实现图片下载ImagesPipeline实 ...

  7. redmine3.2 的部署

    安装libyaml [root@ ~]#wget http://pyyaml.org/download/libyaml/yaml-0.1.4.tar.gz -O /dist/dist/yaml-0.1 ...

  8. spring boot @Scheduled未生效原因以及相关坑、及相对其他定时任务架构的优势

    在spring boot中,支持多种定时执行模式(cron, fixRate, fixDelay),在Application或者其他Autoconfig上增加@EnableScheduling注解开启 ...

  9. 【题解】Luogu P3217 [HNOI2011]数矩形

    原题链接:P3217 [HNOI2011]数矩形 什么??!怎么又是计算几何,您钛毒瘤了-- 这道题真的是毒瘤 凸包?旋转卡壳? 看一下数据,N<=1500? 暴力 没错,就是暴力,N^2没毛病 ...

  10. 实现定时器定时 1 秒钟,LED 亮灭显示

    实现定时器定时 1 秒钟,LED 亮灭显示 要求 每隔一秒钟,实现LED灯的显隐转换 实验代码 /*************************************************** ...