Live2D

2022/11/20 集训题解 Longest Loose Segment

link

Description

定义 \(a_{1,2,...,m}\) 为好序列当且仅当 \(\max a_i+\min a_i>m\),给出一个长度为 \(n\) 的序列,问最长好序列子段长度。有 \(T\) 次修改。

\(n\le 10^6,T \le 30\)

Solution

我们考虑建出小根堆笛卡尔树,关键性结论为:对于一个节点对应的区间,我们只用考虑最大值一边取完了的情况。

考虑证明,可以发现的是我们肯定优先填一边再填一边,因为我们可以把最大值较小的一边的长度接在另一边,这样最大值不变。对于填不完一边的情况,可以发现我们可以不选最小值,在另外一边增加一个,可以发现这样一定不劣,这样就会在子树考虑到。另外,如果取不了最大值一侧,可以发现,如果另外一侧取得到,那么我们相同长度接在以最大值开始的区间,可以发现一定不劣,所以会在子树内考虑到。

综上,我们可以单次 \(\Theta(n)\) 解决这个问题。

Code

#include <bits/stdc++.h>
using namespace std;
     
#define Int register int
#define int long long
#define MAXN 1000005

// char buf[1<<21],*p1=buf,*p2=buf;
// #define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}

int n,m,ans,top,sta[MAXN],a[MAXN],siz[MAXN],mxv[MAXN],lson[MAXN],rson[MAXN];

void dfs (int u){
	mxv[u] = a[u],siz[u] = 1;
	if (lson[u]) dfs (lson[u]),chkmax (mxv[u],mxv[lson[u]]),siz[u] += siz[lson[u]];
	if (rson[u]) dfs (rson[u]),chkmax (mxv[u],mxv[rson[u]]),siz[u] += siz[rson[u]];
	if (siz[u] == 1){
		if (2 * a[u] > 1) chkmax (ans,1ll);
		return ;
	}
	int p = mxv[lson[u]] > mxv[rson[u]] ? lson[u] : rson[u];
	if (siz[p] + 1 < a[u] + mxv[p]) chkmax (ans,siz[p] + 1 + min (a[u] + mxv[p] - siz[p] - 2,siz[lson[u] ^ rson[u] ^ p]));
}

void solve (){
	top = ans = 0;
	for (Int i = 1;i <= n;++ i){
		lson[i] = rson[i] = 0;
		while (top && a[sta[top]] > a[i]) lson[i] = sta[top --];
		if (top) rson[sta[top]] = i;
		sta[++ top] = i;
	}
	dfs (sta[1]),write (ans),putchar ('\n');
}

signed main(){
	read (n,m);
	for (Int x = 1;x <= n;++ x) read (a[x]);
	solve ();
	while (m --> 0){
		int K;read (K);
		for (Int i = 1,x,y;i <= K;++ i) read (x,y),swap (a[x],a[y]);
		solve ();
	}
	return 0;
}
posted @ 2022-11-20 16:44  Dark_Romance  阅读(55)  评论(0编辑  收藏  举报