【bzoj2653】middle 可持久化线段树区间合并
题目描述
输入
输出
Q行依次给出询问的答案。
样例输入
5
170337785
271451044
22430280
969056313
206452321
3
3 1 0 2
2 3 1 4
3 1 4 0
样例输出
271451044
271451044
969056313
题解
可持久化线段树区间合并(断句为:可持久化线段树/区间合并)
首先离散化,然后一眼二分,问题转化为:求是否存在一个左端点在 $[a,b]$ ,右端点在 $[c,d]$ 的区间,使得区间内大于等于 $mid$ 的数的个数 $\ge$ 小于 $mid$ 的数的个数。
如果把大于等于 $mid$ 的数看作 $+1$ ,小于 $mid$ 的数看作 $-1$ ,那么就是要找一段满足端点限制的区间,使得区间和大于等于 $0$ 。
也就是说求出满足条件的区间中最大区间和,判断其是否大于等于 $0$ 即可。
考虑怎么找出满足条件的区间中最大区间和:必选段为 $[b,c]$ ,剩下的是 $[a,b-1]$ 中包含右端点的最大连续子段和以及 $[c+1,d]$ 中包含左端点的最大连续子段和。
于是使用线段树区间合并来维护区间和、包含左&右端点的最大连续子段和。
但是不能对于每个二分的 $mid$ 维护一棵线段树。由于 $mid$ 从 $0$ 变化到 $n$ 的过程中,修改的总次数为 $n$ ,因此可以对每一个权值 $mid$ 开一棵可持久化线段树来维护。
于是这就是可持久化线段树区间合并?
时间复杂度 $O(n\log^2 n)$
PS:不需要从大到小排序.. 代码瞎写的..
#include <cstdio>
#include <algorithm>
#define N 20010
#define lson l , mid , ls[x]
#define rson mid + 1 , r , rs[x]
using namespace std;
struct node
{
int w , id;
bool operator<(const node &a)const {return w > a.w;}
}v[N];
struct data
{
int ts , lv , rv;
data() {ts = lv = rv = 0;}
friend data operator+(const data &a , const data &b)
{
data ans;
ans.ts = a.ts + b.ts;
ans.lv = max(a.lv , a.ts + b.lv);
ans.rv = max(b.rv , b.ts + a.rv);
return ans;
}
}a[N * 50];
int p[4] , ref[N] , top , ls[N * 50] , rs[N * 50] , tot , root[N];
inline void pushup(int x)
{
a[x] = a[ls[x]] + a[rs[x]];
}
void build(int l , int r , int &x)
{
x = ++tot;
if(l == r)
{
a[x].ts = -1 , a[x].lv = a[x].rv = 0;
return;
}
int mid = (l + r) >> 1;
build(lson) , build(rson);
pushup(x);
}
void update(int p , int l , int r , int x , int &y)
{
y = ++tot;
if(l == r)
{
a[y].ts = a[y].lv = a[y].rv = 1;
return;
}
int mid = (l + r) >> 1;
if(p <= mid) rs[y] = rs[x] , update(p , lson , ls[y]);
else ls[y] = ls[x] , update(p , rson , rs[y]);
pushup(y);
}
data query(int b , int e , int l , int r , int x)
{
if(b <= l && r <= e) return a[x];
int mid = (l + r) >> 1;
if(e <= mid) return query(b , e , lson);
else if(b > mid) return query(b , e , rson);
else return query(b , e , lson) + query(b , e , rson);
}
int main()
{
int n , m , i , l , r , mid , ans = 0;
scanf("%d" , &n);
for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &v[i].w) , v[i].id = i;
sort(v + 1 , v + n + 1);
build(1 , n , root[0]);
for(i = 1 ; i <= n ; i ++ )
{
if(v[i].w != ref[top]) ref[++top] = v[i].w , root[top] = root[top - 1];
update(v[i].id , 1 , n , root[top] , root[top]);
}
scanf("%d" , &m);
while(m -- )
{
for(i = 0 ; i < 4 ; i ++ ) scanf("%d" , &p[i]) , p[i] = (p[i] + ans) % n + 1;
sort(p , p + 4);
l = 1 , r = top;
while(l <= r)
{
mid = (l + r) >> 1;
if(query(p[1] , p[2] , 1 , n , root[mid]).ts
+ query(p[0] , p[1] - 1 , 1 , n , root[mid]).rv
+ query(p[2] + 1 , p[3] , 1 , n , root[mid]).lv >= 0)
ans = ref[mid] , r = mid - 1;
else l = mid + 1;
}
printf("%d\n" , ans);
}
return 0;
}
【bzoj2653】middle 可持久化线段树区间合并的更多相关文章
- [BZOJ 2653] middle(可持久化线段树+二分答案)
[BZOJ 2653] middle(可持久化线段树+二分答案) 题面 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序 ...
- POJ 3667 Hotel(线段树 区间合并)
Hotel 转载自:http://www.cnblogs.com/scau20110726/archive/2013/05/07/3065418.html [题目链接]Hotel [题目类型]线段树 ...
- HDU 3911 线段树区间合并、异或取反操作
题目:http://acm.hdu.edu.cn/showproblem.php?pid=3911 线段树区间合并的题目,解释一下代码中声明数组的作用: m1是区间内连续1的最长长度,m0是区间内连续 ...
- HDU 3911 Black And White(线段树区间合并+lazy操作)
开始以为是水题,结果...... 给你一些只有两种颜色的石头,0为白色,1为黑色. 然后两个操作: 1 l r 将[ l , r ]内的颜色取反 0 l r 计算[ l , r ]内最长连续黑色石头的 ...
- HYSBZ 1858 线段树 区间合并
//Accepted 14560 KB 1532 ms //线段树 区间合并 /* 0 a b 把[a, b]区间内的所有数全变成0 1 a b 把[a, b]区间内的所有数全变成1 2 a b 把[ ...
- poj3667 线段树 区间合并
//Accepted 3728 KB 1079 ms //线段树 区间合并 #include <cstdio> #include <cstring> #include < ...
- hdu3911 线段树 区间合并
//Accepted 3911 750MS 9872K //线段树 区间合并 #include <cstdio> #include <cstring> #include < ...
- 线段树(区间合并) POJ 3667 Hotel
题目传送门 /* 题意:输入 1 a:询问是不是有连续长度为a的空房间,有的话住进最左边 输入 2 a b:将[a,a+b-1]的房间清空 线段树(区间合并):lsum[]统计从左端点起最长连续空房间 ...
- HDU 3308 LCIS (线段树区间合并)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 题目很好懂,就是单点更新,然后求区间的最长上升子序列. 线段树区间合并问题,注意合并的条件是a[ ...
随机推荐
- 20145209刘一阳《网络对抗》实验五:MSF基础应用
20145209刘一阳<网络对抗>实验五:MSF基础应用 主动攻击 首先,我们需要弄一个xp sp3 English系统的虚拟机,然后本次主动攻击就在我们kali和xp之间来完成. 然后我 ...
- 优步UBER司机全国各地奖励政策汇总 (2月15日-2月21日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- 北京Uber优步司机奖励政策(2月26日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- mysql索引 b+树
1.B+树基本概念 B+树的语言定义比较复杂,简单的说是为磁盘存取设计的平衡二叉树 网上经典图,黄色p1 p2 p3代表指针,蓝色的代表磁盘,里面包含数据项,第一层17,35,p1就代表小于17的,p ...
- 「日常训练」Paths and Trees(Codeforces Round 301 Div.2 E)
题意与分析 题意是这样的,定义一个从某点出发的所有最短路方案中,选择边权和最小的最短路方案,称为最短生成树. 现在求一棵最短生成树,输出总边权和与选取边的编号. 我们首先要明白这样一个结论:对一个图求 ...
- .net 使用com组件操作word遇到的一些问题
1.警告: 方法“Microsoft.Office.Interop.Word._Document.Close(ref object, ref object, ref object)”和非方法“Micr ...
- JVM之G1收集器
Garbage-First,面向服务端的垃圾收集器. 并行与并发:充分利用多核环境减少停顿时间, 分代收集:不需要配合其它收集器 空间整合:整体上看属于标记整理算法,局部(region之间)数据复制算 ...
- 【转载】android 常用开源框架
对于Android初学者以及对于我们菜鸟,这些大神们开发的轻量级框架非常有用(更别说开源的了). 下面转载这10个框架的介绍:(按顺序来吧没有什么排名). 一. Afinal 官方介绍: Afina ...
- APUE学习笔记3_文件IO
APUE学习笔记3_文件IO Unix中的文件IO函数主要包括以下几个:open().read().write().lseek().close()等.这类I/O函数也被称为不带缓冲的I/O,标准I/O ...
- Linux系统inotify工具安装配置
inotify主要功能 Inotify 是一个 Linux特性,它监控文件系统操作,比如读取.写入和创建.Inotify 反应灵敏,用法非常简单,并且比 cron 任务的繁忙轮询高效得多.学习如何将 ...