重生之 CF2126G2. Big Wins! (hard version)

$$ 高考结束了,前退役 \text{Oie} 要开始 \text{Ta} 的 \text{ACM} 生活了。 $$

前置:一个区间的 \(med \geq x\) 等价于若将 \(a_i \geq x\) 的元素赋值为 \(1\) ,其余赋值为 \(-1\) ,元素之和 \(\geq 0\)

本题没有限制\(\text{ a[i]}\) 的大小,也就是没有限制 \(med\) 的大小。第一个想法是枚举 \(\text{min}\) 值,对每一个 \(a_i = min\) 的位置用单调栈或者笛卡尔树计算能保持最小值的 \(l_i\) 和 \(r_i\) ,然后我们考虑这个区间内的 \(med\),复杂度为 \(O(n^2 \log n)\) 。

我们考虑如果从小到大枚举 \(med\) ,依次更新每个 \(min\) 值对应的 \(med\) 看能否取到,很可惜,这样也只能做到 \(O(n^2 \log n)\)。

但是我们注意到,刚刚的对每个min求med 是没有必要的,我们只是想知道他们的最大差值,那么我们不妨从小到大枚举每个\(min\),并且在线段树中进行修改,对于同一个\(min\),我们可以不断尝试让 \(med\) 增大,直到顶到上限。同时由于我们枚举的区间的 \(min\) 值不断上升,若想要更新答案,\(med\) 值必然要增大才会有可能更优,二者均单调递增,复杂度优化至 \(O(n\log n)\)
点击查看代码

cpp 复制代码
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int T,n,a[N];vector<int> pos[N];
int al[N],ar[N];
inline void read(int &x)
{
	int f=1;char c;
	for(x=0,c=getchar();c<'0'||c>'9';c=getchar()) if(c=='-') f=-1;
	for(;c>='0'&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48); x*=f;
}
inline int mn(int _x,int _y){return _x<_y?_x:_y;}
inline int mx(int _x,int _y){return _x>_y?_x:_y;}
inline int ab(int _x){return _x<0?-_x:_x;}

struct node{
	int sum;int premx;int sufmx;
};
node val[N<<2];
inline node pushup(node a,node b){
	node c;
	c.sum=a.sum+b.sum;
	c.premx=mx(a.premx,a.sum+b.premx);
	c.sufmx=mx(a.sufmx+b.sum,b.sufmx);
	return c;
}
inline void update(int x,int l,int r,int pos){
	if(l==r){val[x]=(node){-1,-1,-1};return ;}
	int mid=l+r>>1;
	if(pos<=mid) update(x<<1,l,mid,pos);
	if(pos>mid) update(x<<1|1,mid+1,r,pos);
	val[x]=pushup(val[x<<1],val[x<<1|1]);
	return ;
}
inline node query(int x,int l,int r,int ql,int qr){
	if(ql>qr) return (node){0,0,0};
	if(ql<=l&&r<=qr) return val[x];
	int mid=l+r>>1;
	if(qr<=mid) return query(x<<1,l,mid,ql,qr);
	else if(ql>mid) return query(x<<1|1,mid+1,r,ql,qr);
	else return pushup(query(x<<1,l,mid,ql,qr),query(x<<1|1,mid+1,r,ql,qr));
}
inline void build(int x,int l,int r){
	val[x]=(node){r-l+1,r-l+1,r-l+1};
	if(l==r) return ;
	int mid=l+r>>1;
	build(x<<1,l,mid);build(x<<1|1,mid+1,r);
	return ;
}
int sta[N],stp;
inline void Solve(){
	read(n);
	for(int i=1;i<=n;i++){
		read(a[i]);pos[i].clear();
	}
	for(int i=1;i<=n;i++) pos[a[i]].push_back(i);
	build(1,1,n);int med=1,ans=0;
	stp=0;
	for(int i=1;i<=n;i++){
		while(stp>=1&&a[sta[stp]]>a[i]){
			ar[sta[stp]]=i-1;--stp;
        }
		sta[++stp]=i;
	}
	while(stp>=1){ar[sta[stp]]=n;--stp;}
	stp=0;
	for(int i=n;i>=1;i--){
		while(stp>=1&&a[sta[stp]]>a[i]){
			al[sta[stp]]=i+1;--stp;
		}
		sta[++stp]=i;
	}
	while(stp>=1){al[sta[stp]]=1;--stp;}

	for(int i=1;i<=n;i++){
		for(int j=0;j<pos[i].size();j++){
			int p=pos[i][j];
			while(med<=n&&mx(query(1,1,n,al[p],p-1).sufmx,0)+(a[p]<med?-1:1)+mx(0,query(1,1,n,p+1,ar[p]).premx)>=0){
				ans=mx(ans,med-a[p]);
				for(int t=0;t<pos[med].size();t++) update(1,1,n,pos[med][t]);
				++med;
			}
		}
	}
	printf("%d\n",ans);return ;
}
int main()
{
	read(T); 
	while(T--) Solve();
	return 0;
}
相关推荐
Savior`L7 天前
Educational Codeforces Round 181 (Rated for Div. 2)
数据结构·c++·算法·codeforces
TL自动机18 天前
Educational Codeforces Round 180 (Rated for Div. 2) C. Coloring Game
codeforces
Closet1232 个月前
Codeforces 2025/6/11 日志
c++·算法·codeforces
keysky2 个月前
「ABC 406 G」Travelling Salesman Problem
线段树·slope trick·数形结合
pystraf2 个月前
LG P9844 [ICPC 2021 Nanjing R] Paimon Segment Tree Solution
数据结构·c++·算法·线段树·洛谷
pystraf3 个月前
P2572 [SCOI2010] 序列操作 Solution
数据结构·算法·线段树·洛谷
pystraf3 个月前
UOJ 228 基础数据结构练习题 Solution
数据结构·c++·算法·线段树
GEEK零零七3 个月前
Leetcode 2158. 每天绘制新区域的数量【Plus题】
算法·leetcode·线段树·并查集
pystraf4 个月前
P10587 「ALFR Round 2」C 小 Y 的数 Solution
数据结构·c++·算法·线段树·洛谷