[CF1539F]Strange Array

Posted Tan_tan_tann

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF1539F]Strange Array相关的知识,希望对你有一定的参考价值。

Strange Array

题解

考虑我们如何求出一个数与这个序列中间数之间的距离。
假设这个序列中有 x x x个数比 a i a_{i} ai大,有 y y y个数与 a i a_{i} ai一样,有 z z z个数比 a i a_{i} ai小。
a i a_{i} ai不小于这个序列的中间数时,它们之间的距离为 y + z − ⌈ x + y + z 2 ⌉ = ⌊ y + z − x 2 ⌋ y+z-\\left\\lceil\\frac{x+y+z}{2}\\right\\rceil=\\left\\lfloor\\frac{y+z-x}{2}\\right\\rfloor y+z2x+y+z=2y+zx
a i a_{i} ai不大于这个序列的中间数时,它们之间的距离为 x + y − ⌊ x + y + z 2 ⌋ = ⌈ x + y − z 2 ⌉ x+y-\\left\\lfloor\\frac{x+y+z}{2}\\right\\rfloor=\\left\\lceil\\frac{x+y-z}{2}\\right\\rceil x+y2x+y+z=2x+yz
我们可以分大于中间数与小于中间数两种情况去求答案。

对于 a i a_{i} ai不小于中间数的答案,我们先将所有数都赋值为 − 1 -1 1,再从 i = 1 i=1 i=1开始,将等于 i i i的数的值赋值为 1 1 1
那么对于 a j = i a_{j}=i aj=i,它的 y + z − x y+z-x y+zx相当于是最大的一段区间和。
我们求最大的区间和可以利用线段树来维护每个位置的前缀,记点 i i i的前缀为 p r e i pre_{i} prei,有
( y + z − x ) m a x = max ⁡ k = j n p r e k − min ⁡ k = 0 j − 1 p r e k (y+z-x)_{max}=\\max_{k=j}^{n}pre_{k}-\\min_{k=0}^{j-1}pre_{k} (y+zx)max=k=jmaxnprekk=0minj1prek
我们可以通过线段树的区间修改来维护前缀,通过线段树的区间最值来求出它的最大/小前缀。
对于 a i a_{i} ai不大于中间数的答案,做法是相同的,只需要从 i = n i=n i=n开始即可。

时间复杂度 O ( n l o g   n ) O\\left(nlog\\,n\\right) O(nlogn)

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
#define lowbit(x) (x&-x)
#define reg register
#define mkpr make_pair
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x3f3f3f3f;
const int mo=1e9+7;
const int iv2=5e8+4;
const int lim=1000000;
const int jzm=2333;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int add(int x,int y){return x+y<mo?x+y:x+y-mo;}
int n,a[MAXN],ans[MAXN];
vector<int>vec[MAXN];
class SegmentTree{
	public:
		int trmx[MAXN<<2],trmn[MAXN<<2],lzy[MAXN<<2];
		void pushup(int rt){
			trmx[rt]=max(trmx[rt<<1],trmx[rt<<1|1]);
			trmn[rt]=min(trmn[rt<<1],trmn[rt<<1|1]);
		}
		void pushdown(int rt,int l,int r){
			if(lzy[rt]){
				int mid=l+r>>1;
				trmx[rt<<1]+=lzy[rt];trmx[rt<<1|1]+=lzy[rt];
				trmn[rt<<1]+=lzy[rt];trmn[rt<<1|1]+=lzy[rt];
				lzy[rt<<1]+=lzy[rt];lzy[rt<<1|1]+=lzy[rt];
				lzy[rt]=0;
			}
		}
		void build(int rt,int l,int r,int aw){
			lzy[rt]=0;if(l==r){trmx[rt]=trmn[rt]=l*aw;return ;}int mid=l+r>>1;
			build(rt<<1,l,mid,aw);build(rt<<1|1,mid+1,r,aw);pushup(rt);
		}
		void modify(int rt,int l,int r,int al,int ar,int aw){
			if(l>r||l>ar||r<al||al>ar)return ;
			if(al<=l&&r<=ar){trmx[rt]+=aw;trmn[rt]+=aw;lzy[rt]+=aw;return ;}
			int mid=l+r>>1;pushdown(rt,l,r);
			if(al<=mid)modify(rt<<1,l,mid,al,ar,aw);
			if(ar>mid)modify(rt<<1|1,mid+1,r,al,ar,aw);
			pushup(rt);
		}
		int queryMax(int rt,int l,int r,int al,int ar){
			if(l>r||l>ar||r<al||al>ar)return -INF;int mid=l+r>>1,res=-INF;
			if(al<=l&&r<=ar)return trmx[rt];pushdown(rt,l,r);
			if(al<=mid)res=max(res,queryMax(rt<<1,l,mid,al,ar));
			if(ar>mid)res=max(res,queryMax(rt<<1|1,mid+1,r,al,ar));
			return res; 
		}
		int queryMin(int rt,int l,int r,int al,int ar){
			if(l>r||l>ar||r<al||al>ar)return INF;int mid=l+r>>1,res=INF;
			if(al<=l&&r<=ar)return trmn[rt];pushdown(rt,l,r);
			以上是关于[CF1539F]Strange Array的主要内容,如果未能解决你的问题,请参考以下文章

CodeForces - 1539F Strange Array(线段树区间合并)

CF1383E Strange Operation

CF 873C Strange Game On Matrix(贪心)

题解 CF1383E Strange Operation

cf842d Vitya and Strange Lesson

CF1270D Strange Device