[CF1539F] Strange Array (线段树)
题面
有一个长度为
n
\tt n
n 的序列
a
\tt a
a ,对于每一个位置
i
∈
[
1
,
n
]
\tt i\in[1,n]
i∈[1,n]:
- 选择一个区间
[
l
,
r
]
\tt[l,r]
[l,r] 满足
1
≤
l
≤
i
≤
r
≤
n
\tt1\leq l\leq i\leq r\leq n
1≤l≤i≤r≤n 。
- 把区间
[
l
,
r
]
\tt[l,r]
[l,r] 中的数拿出来(很明显包括
a
i
\tt a_i
ai) ,从小到大排序,值相同的可以随意排。
- 中间位置定义为:
{
l
e
n
g
t
h
+
1
2
,
(
l
e
n
g
t
h
%
2
=
1
)
l
e
n
g
t
h
2
+
1
,
(
l
e
n
g
t
h
%
2
=
0
)
\left\{\begin{array}{cc}\frac{\tt length+1}{2}, & (\tt length\,\%\,2=1)\\\frac{\tt length}{2}+1, & (\tt length\,\%\,2=0)\end{array}\right.
{2length+1,2length+1,(length%2=1)(length%2=0),即
⌈
l
e
n
g
t
h
+
1
2
⌉
\tt\left\lceil\frac{length+1}{2}\right\rceil
⌈2length+1⌉ 。
- 位置
i
\tt i
i 的奇怪度就是
∣
a
i
排
序
后
的
位
置
−
中
间
位
置
∣
\tt|a_i排序后的位置-中间位置|
∣ai排序后的位置−中间位置∣ 。
给出
n
\tt n
n 和序列
a
\tt a
a ,每个位置
i
\tt i
i 的所选区间
[
l
i
,
r
i
]
\tt[l_i,r_i]
[li,ri] 随意,但是你得输出位置
i
\tt i
i 的最大奇怪度。
1
≤
n
≤
200
000
,
1
≤
a
i
≤
n
\tt1\leq n\leq 200\,000~,~1\leq a_i\leq n
1≤n≤200000 , 1≤ai≤n 。
题解
定义
S
1
\tt S_1
S1 为区间
[
l
,
r
]
\tt[l,r]
[l,r] 中严格小于
a
i
\tt a_i
ai 的元素个数,
S
2
\tt S_2
S2 为区间
[
l
,
r
]
\tt[l,r]
[l,r] 中等于
a
i
\tt a_i
ai 的元素个数(包括它自己),
S
3
\tt S_3
S3 为区间
[
l
,
r
]
\tt[l,r]
[l,r] 中严格大于
a
i
\tt a_i
ai 的元素个数,那么位置
i
\tt i
i 的奇怪度就是
max
{
(
S
1
+
S
2
)
−
⌈
(
S
1
+
S
2
)
+
S
3
+
1
2
⌉
⌈
S
1
+
(
S
2
+
S
3
)
+
1
2
⌉
−
(
S
1
+
1
)
\max\left\{\begin{matrix} \tt (S_1+S_2)-\left\lceil \frac{(S_1+S_2)+S_3+1}{2} \right\rceil\\ \tt \left\lceil \frac{S_1+(S_2+S_3)+1}{2} \right\rceil-(S_1+1) \end{matrix}\right.
max⎩⎨⎧(S1+S2)−⌈2(S1+S2)+S3+1⌉⌈2S1+(S2+S3)+1⌉−(S1+1)
这里我都是忽略了绝对值符号的,因为第一行就是假设的
a
i
\tt a_i
ai 在中间位置后面,第二行假设的在前面。这两种情况对于与自己相同的元素利用不同,假设
a
i
\tt a_i
ai 在后面时,相同的尽量放前面(认为它们比
a
i
\tt a_i
ai 小),否则尽量放后面(认为它们比
a
i
\tt a_i
ai 大)。于是就有了上面的式子。
然后我们可以发现一个性质:同时在比
a
i
\tt a_i
ai 大的和比
a
i
\tt a_i
ai 小的数中各减去相同数量的元素后,答案不变。相当于把排序后的序列前后各掐掉等长的一段(不去掉
a
i
\tt a_i
ai),此时中间位置和
a
i
\tt a_i
ai 的相对位置不变,奇怪度也不变,这个性质不难理解,看上面的式子也明白了。
那么说,对我们有用的信息就只有两者的差了!只要知道了差,然后假设较小者为
0
\tt0
0 ,再带入上述式子,得到的结果是一样的。
不妨认为与
a
i
\tt a_i
ai 相等的都小于它,接下来:
先考虑只求一个位置
i
\tt i
i 怎么做。我们把小于
a
i
\tt a_i
ai 的位置赋为
1
\tt1
1 ,大于它的位置赋为
−
1
\tt-1
−1 ,处理前缀和数组
s
u
m
\tt sum
sum ,那么就是求
∣
s
u
m
r
−
s
u
m
l
−
1
∣
\tt|sum_r-sum_{l-1}|
∣sumr−suml−1∣ 的最大值。此时,由于限定了
1
≤
l
≤
i
≤
r
≤
n
\tt1\leq l\leq i\leq r\leq n
1≤l≤i≤r≤n,我们在两者的范围内分别找最大或最小的
s
u
m
r
\tt sum_r
sumr 以及
s
u
m
l
−
1
\tt sum_{l-1}
suml−1 的值,就可以解决问题了。
如果是多个位置
i
\tt i
i 呢?按照值排序,建立主席树是一个办法,但是没有必要,这道题可是离线的。我们只需要从小到大计算,每次在一个线段树上维护
s
u
m
\tt sum
sum 数组和查询就行了。需要注意,值相同的位置要先全部修改,再挨个查询。
假设与
a
i
\tt a_i
ai 相等的大于它也一样,就是值相同的位置要查询后再修改罢了。
时间复杂度
Θ
(
n
log
n
)
\tt \Theta(n\log n)
Θ(nlogn) 。
CODE
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 200005
#define DB double
#define LL long long
#define ENDL putchar('\n')
#define lowbit(x) ((-x) & (x))
LL read() {
LL f=1,x=0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
int n,m,i,j,s,o,k;
int a[MAXN];
vector<int> bu[MAXN];
int tre[MAXN<<2],tre2[MAXN<<2],lz[MAXN<<2],M;
void maketree(int n) {
M=1;while(M<n+2)M<<=1;
}
void addtree(int l,int r,int y) {
if(l > r) return ;
int s=M+l-1,t=M+r+1;
while(s || t) {
if(s<M) {
tre[s] = max(tre[s<<1],tre[s<<1|1])+lz[s];
tre2[s] = min(tre2[s<<1],tre2[s<<1|1])+lz[s];
}
if(t<M) {
tre[t] = max(tre[t<<1],tre[t<<1|1])+lz[t];
tre2[t] = min(tre2[t<<1],tre2[t<<1|1])+lz[t];
}
if((s>>1) ^ (t>>1)) {
if(!(s & 1)) tre[s^1] += y,tre2[s^1] += y,lz[s^1] += y;
if(t & 1) tre[t^1] += y,tre2[t^1] += y,lz[t^1] += y;
}
s >>= 1;t >>= 1;
}
return ;
}
int findmax(int l,int r) {
if(l > r) return -0x3f3f3f3f;
int s=M+l-1,t=M+r+1;
int ls = -0x3f3f3f3f,rs = -0x3f3f3f3f;
while(s || t) {
if(s<M) ls += lz[s];
if(t<M) rs += lz[t];
if((s>>1) ^ (t>>1)) {
if(!(s & 1)) ls = max(tre[s^1],ls);
if(t & 1) rs = max(tre[t^1],rs);
}
s >>= 1;t >>= 1;
}
return max(ls,rs);
}
int findmin(int l,int r) {
if(l > r) return 0x3f3f3f3f;
int s=M+l-1,t=M+r+1;
int ls = 0x3f3f3f3f,rs = 0x3f3f3f3f;
while(s || t) {
if(s<M) ls += lz[s];
if(t<M) rs += lz[t];
if((s>>1) ^ (t>>1)) {
if(!(s & 1)) ls = min(tre2[s^1],ls);
if(t & 1) rs = min(tre2[t^1],rs);
}
s >>= 1;t >>= 1;
}
return min(ls,rs);
}
int as[MAXN];
int main() {
n = read();
maketree(n);
for(int i = 1;i <= n;i ++) {
a[i] = read();
bu[a[i]].push_back(i);
addtree(i,n,-1);
}
for(int i = 1;i <= n;i ++) {
for(int j = 0;j <(int)bu[i].size();j ++) { // -1 -> 1
int y = bu[i][j];
int ll = max(0,findmax(1,y-1)),rr = findmin(y,n);
int mx = ll-rr;
as[y] = max(as[y],(mx+2)/2-1);
}
for(int j = 0;j <(int)bu[i].size();j ++) {
int y = bu[i][j];
addtree(y,n,2);
}
for(int j = 0;j <(int)bu[i].size();j ++) {
int y = bu[i][j];
int ll = min(0,findmin(1,y-1)),rr = findmax(y,n);
int mi = rr-ll;
as[y] = max(as[y],mi-(mi+2)/2);
}
}
for(int i = 1;i <= n;i ++) {
printf("%d ",as[i]);
}ENDL;
return 0;
}
[CF1539F] Strange Array (线段树)的更多相关文章
- CF1539F Strange Array
这玩意为啥是紫. 考虑对每个小于\(x\)的数值设为1,大于\(x\)的数值设为-1. 那么对于答案要求的就是绝对值最大的连续段. 线段树是很显然的. 考虑我们不能对每个数都进行一遍重构,这样就退化到 ...
- [Codeforces 266E]More Queries to Array...(线段树+二项式定理)
[Codeforces 266E]More Queries to Array...(线段树+二项式定理) 题面 维护一个长度为\(n\)的序列\(a\),\(m\)个操作 区间赋值为\(x\) 查询\ ...
- 【Codeforces718C】Sasha and Array 线段树 + 矩阵乘法
C. Sasha and Array time limit per test:5 seconds memory limit per test:256 megabytes input:standard ...
- codeforces 719E E. Sasha and Array(线段树)
题目链接: E. Sasha and Array time limit per test 5 seconds memory limit per test 256 megabytes input sta ...
- Codeforces 482B Interesting Array(线段树)
题目链接:Codeforces 482B Interesting Array 题目大意:给定一个长度为N的数组,如今有M个限制,每一个限制有l,r,q,表示从a[l]~a[r]取且后的数一定为q,问是 ...
- Codeforces 1114F Please, another Queries on Array? 线段树
Please, another Queries on Array? 利用欧拉函数的计算方法, 用线段树搞一搞就好啦. #include<bits/stdc++.h> #define LL ...
- 2019ccpc网络赛hdu6703 array(线段树)
array 题目传送门 解题思路 操作1是把第pos个位置上的数加上\(10^7\),操作2是找到区间[1,r]中没有且大于k的最小的数.注意到k的范围是小于等于n的,且n的范围是\(10^5\),远 ...
- Codeforces Round #275 Div.1 B Interesting Array --线段树
题意: 构造一个序列,满足m个形如:[l,r,c] 的条件. [l,r,c]表示[l,r]中的元素按位与(&)的和为c. 解法: 线段树维护,sum[rt]表示要满足到现在为止的条件时该子树的 ...
- 暑假集训单切赛第一场 CF 266E More Queries to Array(线段树+二项式展开式)
比赛时,第二题就是做的这个,当时果断没仔细考虑,直接用线段树暴力求.结果易想而知,超时了. 比赛后搜了搜题解,恍然大悟. 思路:显然用线段树,但是由于每次查询都会有变,所以不可能存储题目中的式子. ...
- Codeforces295A - Greg and Array(线段树的成段更新)
题目大意 给定一个序列a[1],a[2]--a[n] 接下来给出m种操作,每种操作是以下形式的: l r d 表示把区间[l,r]内的每一个数都加上一个值d 之后有k个操作,每个操作是以下形式的: x ...
随机推荐
- Nginx安装及支持https代理配置和禁用TSLv1.0、TSLv1.1配置
Linux安装Nginx Nginx安装及支持https代理配置和禁用TSLv1.0.TSLv1.1配置. 下载安装包 [root@localhost ~]# wget http://nginx.or ...
- Redis的使用(二)
一.redis简单应用 其实在写这个redis专题时我想了很久,我觉得redis没什么好说的,因为现在是个人都会用redis,但是我在写netty专题时发现,netty里面很多东西和概念有很多跟red ...
- 搭建SVN服务器-腾讯云
检查服务器SVN服务器 svn --version 出现版本号说明已安装 安装SVN yum install subversion 创建版本库 svnadmin create /opt/svn/rep ...
- FICO 常用事务码
1.SAP配置流程 1.定义,定义组织,概念,比如FI中定义公司代码,会计科目表,年度变式.SAP中有大量的定义过程. 2.分配,把会计科目表/公司/年度变式等参数分配到公司代码,逻辑组织,基本实现框 ...
- Linux 文件权限相关知识
文件权限说明 Linux中的文件能否被访问和工具(程序)无关,和访问的用户身份有关(谁去运行这个程序) 进程的发起者(谁去运行这个程序). 进程的发起者若是文件的所有者: 拥有文件的属主权限 进程的发 ...
- 关于我用python表白成功这件事【表白成功】
520,并非情人所属, 我们可以表白万物, 不管什么时候, 这都是一个特别的日子, 今天,我要表白所有, 心里有我的人! 在这个充满幸福的日子里, 我要把最美好的祝福, 送给心里有我的每一个人: 祝愿 ...
- NC18979 毒瘤xor
NC18979 毒瘤xor 题目 题目描述 小a有 \(N\) 个数 \(a_1, a_2, ..., a_N\) ,给出 \(q\) 个询问,每次询问给出区间 \([L, R]\) ,现在请你找到一 ...
- 数据孤岛下的新破局 Real Time DaaS:面向 AP+TP 业务的数据平台架构
从传统数仓,到大数据平台,再到数据中台和湖仓一体新数据平台,在日益加重的数据孤岛困扰下,面向AP场景的解决方案可谓浩如烟海.但实际上,企业在TP类型业务上的投入和AP的比率却高达9:1,为什么没有为T ...
- 等待唤醒机制代码实现_包子类&包子铺类和等待唤醒机制代码实现_吃货类&测试类
资源类:包子类 设置包子的属性 皮 陷 包子的状态:有 true 没有 false public class BaoZi { //皮 String pi; //陷 String xian; //包子的 ...
- Redis 渐进集群介绍
redis 凭借着强大的功能和可靠的稳定性,应用场景越来越广.逐渐成为软件开发工程师必备的技能之一. 本篇文章,暂不做基本功能的介绍.直接教大家如何部署redis集群. 集群演进主要分为2部分. 一. ...