BZOJ 2653 middle 二分答案+可持久化线段树
题目大意:有一个序列,包含多次询问。询问区间左右端点在规定区间里移动所得到的最大中位数的值。
考虑对于每个询问,如何得到最优区间?枚举显然是超时的,只能考虑二分。
中位数的定义是在一个序列中,比中位数小的数跟比它大的数一样多,由于我们要求的是最大的中位数,自然希望能找到一个区间,使得该区间内比该中位数大的数尽量多。
二分中位数k,假设比k小的数记为-1,其余的数记为1,那么我们就是要寻找最大连续子序列和,若找到的最大的和>=0,则当前的k就是合法的。
最大连续子序列和可以用线段树来维护,由于存在多组询问,每次建一棵线段树很慢,我们选择建主席树。初始时,把数按从小到大排好序,全部的数记为1,做到第i个数时,将第i-1个数记为-1,以此做下去。
那么这样最终二分到的答案会不会不在指定的区间范围之中呢?
肯定是不存在的,我们可以分类讨论。
n为偶数:n = 4时,0 1 2 3,中位数的位置为2,如果答案在1-2之间,则会有更优的答案;如果在2-3之间,显然是不可能的。
n为奇数:n = 3时,0 1 2 3 4,中位数的位置为2,分析同上。
#include <cstdio>
#include <cstdlib>
#include <algorithm> using namespace std; typedef long long LL;
const int maxn = ;
int n, a[maxn], b[maxn], root[maxn], q[];
struct Tree
{
int cnt;
int ml[maxn*], mr[maxn*], sum[maxn*], ls[maxn*], rs[maxn*];
Tree()
{
cnt = ;
}
void pushup(int rt)
{
ml[rt] = max(ml[ls[rt]], sum[ls[rt]]+ml[rs[rt]]);
mr[rt] = max(mr[rs[rt]], sum[rs[rt]]+mr[ls[rt]]);
sum[rt] = sum[ls[rt]]+sum[rs[rt]];
}
void build(int rt, int l, int r)
{
if (l == r)
{
ml[rt] = mr[rt] = sum[rt] = ;
return ;
}
int mid = (l+r)>>;
ls[rt] = ++cnt, build(ls[rt], l, mid);
rs[rt] = ++cnt, build(rs[rt], mid+, r);
pushup(rt);
}
void update(int las_rt, int rt, int l, int r, int p, int d)
{
if (l == r)
{
ml[rt] = mr[rt] = sum[rt] = d;
return ;
}
int mid = (l+r)>>;
if (p <= mid)
{
ls[rt] = ++cnt, rs[rt] = rs[las_rt];
update(ls[las_rt], ls[rt], l, mid, p, d);
}
else
{
ls[rt] = ls[las_rt], rs[rt] = ++cnt;
update(rs[las_rt], rs[rt], mid+, r, p, d);
}
pushup(rt);
}
int query_sum(int rt, int l, int r, int L, int R)
{
if (L <= l && r <= R)
return sum[rt];
int mid = (l+r)>>, ret = ;
if (L <= mid)
ret += query_sum(ls[rt], l, mid, L, R);
if (R > mid)
ret += query_sum(rs[rt], mid+, r, L, R);
return ret;
}
int query_ml(int rt, int l, int r, int L, int R)
{
if (L <= l && r <= R)
return ml[rt];
int mid = (l+r)>>;
if (R <= mid)
return query_ml(ls[rt], l, mid, L, R);
else
if (L > mid)
return query_ml(rs[rt], mid+, r, L, R);
else
return max(query_ml(ls[rt], l, mid, L, R), query_sum(ls[rt], l, mid, L, R)+query_ml(rs[rt], mid+, r, L, R));
}
int query_mr(int rt, int l, int r, int L, int R)
{
if (L <= l && r <= R)
return mr[rt];
int mid = (l+r)>>;
if (R <= mid)
return query_mr(ls[rt], l, mid, L, R);
else
if (L > mid)
return query_mr(rs[rt], mid+, r, L, R);
else
return max(query_mr(rs[rt], mid+, r, L, R), query_sum(rs[rt], mid+, r, L, R)+query_mr(ls[rt], l, mid, L, R));
}
}T; bool cmp(const int &AI, const int &BI)
{
return a[AI] < a[BI];
} void build_tree()
{
root[] = ++T.cnt;
T.build(root[], , n);
for (int i = ; i <= n; ++i)
{
root[i] = ++T.cnt;
T.update(root[i-], root[i], , n, b[i-], -);
}
} bool check(int k, int q1, int q2, int q3, int q4)
{
int sum = ;
if (q2+ < q3)
sum += T.query_sum(root[k], , n, q2+, q3-);
sum += T.query_mr(root[k], , n, q1, q2);
sum += T.query_ml(root[k], , n, q3, q4);
return sum >= ;
} int main()
{
scanf("%d", &n);
for (int i = ; i <= n; ++i)
scanf("%d", &a[i]), b[i] = i;
sort(b+, b+n+, cmp);
build_tree();
int ans = ;
int task;
scanf("%d", &task);
while (task --)
{
scanf("%d %d %d %d", &q[], &q[], &q[], &q[]);
for (int i = ; i <= ; ++i)
q[i] = (q[i]+ans)%n+;
sort(q+, q++);
int l = , r = n;
while (l < r)
{
int mid = (l+r+)>>;
if (check(mid, q[], q[], q[], q[]))
l = mid;
else
r = mid-;
}
ans = a[b[l]];
printf("%d\n", ans);
}
return ;
}
BZOJ 2653 middle 二分答案+可持久化线段树的更多相关文章
- bzoj 2653 二分答案+可持久化线段树
首先离散化,然后我们知道如果对于一个询问的区间[l1,r1],[l2,r2],我们二分到一个答案x,将[l1,r2]区间中的元素大于等于x的设为1,其余的设为-1,那么如果[l1,r1]的最大右区间和 ...
- BZOJ2653middle——二分答案+可持久化线段树
题目描述 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个 长度为n的序列s.回答Q个这样的询问:s的左端点在[a,b]之间,右端点在 ...
- bzoj 2653 middle 二分答案 主席树判定
判断中位数是否可行需要将当前的解作为分界,大于其的置为1,小于为-1,然后b-c必选,ab,cd可不选,这个用线段树判定就好 但不能每次跑,所以套主席树,按权值排序,构建主席树,更新时将上一个节点改为 ...
- [BZOJ 3123] [SDOI 2013]森林(可持久化线段树+并查集+启发式合并)
[BZOJ 3123] [SDOI 2013]森林(可持久化线段树+启发式合并) 题面 给出一个n个节点m条边的森林,每个节点都有一个权值.有两种操作: Q x y k查询点x到点y路径上所有的权值中 ...
- bzoj 3514: GERALD07加强版 lct+可持久化线段树
题目大意: N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. 题解: 这道题考试的时候没想出来 于是便爆炸了 结果今天下午拿出昨天准备的题表准备做题的时候 题表里就有这题 ...
- BZOJ 3653: 谈笑风生(DFS序+可持久化线段树)
首先嘛,还是太弱了,想了好久QAQ 然后,这道题么,明显就是求sigma(size[x]) (x是y的儿子且层树小于k) 然后就可以发现:把前n个节点按深度建可持久化线段树,就能用前缀和维护了 其实不 ...
- bzoj 4504: K个串 可持久化线段树+堆
题目: Description 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一 个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次). 兔子们想 ...
- BZOJ 3524 [Poi2014]Couriers(可持久化线段树)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3524 [题目大意] 给一个长度为n的序列a.1≤a[i]≤n. m组询问,每次询问一个 ...
- BZOJ 3218 A + B Problem (可持久化线段树+最小割)
做法见dalao博客 geng4512的博客, 思路就是用线段树上的结点来进行区间连边.因为有一个只能往前面连的限制,所以还要可持久化.(duliu) 一直以来我都是写dinicdinicdinic做 ...
随机推荐
- tf.reduce_sum()_tf.reduce_mean()_tf.reduce_max()
根据官方文档: reduce_sum应该理解为压缩求和,用于降维 tf.reduce_sum(input_tensor,axis=None,keepdims=None,name=None,reduct ...
- 蓝色的oa模板html_综合信息服务管理平台OA模板——后台
链接:http://pan.baidu.com/s/1qXGGOAK 密码:2otu
- Linux下搜索命令
linux下用于查找文件的5个命令,有需要的朋友可以参考下.包括find,whereis,locate,which与type. linux下用于查找文件的5个命令,有需要的朋友可以参考下.包括find ...
- LCD常用接口原理【转】
转自:http://blog.csdn.net/wocao1226/article/details/23870149 LCD常用接口原理 点击打开链接 点击打开链接 点击打开链接 点击打开链接 点击打 ...
- 【swupdate文档 三】SWUpdate: 嵌入式系统的软件升级
SWUpdate: 嵌入式系统的软件升级 概述 本项目被认为有助于从存储媒体或网络更新嵌入式系统.但是,它应该主要作为一个框架来考虑,在这个框架中可以方便地向应用程序添加更多的协议或安装程序(在SWU ...
- 概述sysfs文件系统【转】
转自:http://blog.csdn.net/npy_lp/article/details/78933292 内核源码:linux-2.6.38.8.tar.bz2 目标平台:ARM体系结构 sys ...
- [转载]锁无关的数据结构与Hazard指针——操纵有限的资源
Lock-Free Data Structures with Hazard Pointers 锁无关的数据结构与Hazard指针----操纵有限的资源 By Andrei Alexandrescu a ...
- (四)Spring 对DAO 的支持
第一节:Spring 对JDBC 的支持 1,配置数据源dbcp: 2,使用JdbcTemplate: 3,JdbcDaoSupport 的使用: 4,NamedParameterJdbcTempla ...
- python datetime 时区(timezone) dateutil
记录下python中的时区问题, 代码如下: 包括datetime.datetime对象使用不同的时区,以及在不同时区间转换. from datetime import datetime from ...
- python lxml教程
目前有很多xml,html文档的parser,如标准库的xml.etree , beautifulsoup , 还有lxml. 都用下来感觉lxml不错,速度也还行,就他了. 围绕三个问题: 问题 ...