2025 ICPC网络赛第一场 L cover

题目链接

给一个长度为 \(n\) 的序列 \(\{a_n\}\)\(m\) 个操作,其中第 \(i\) 个操作是把区间 \([l_i,r_i]\) 都赋值为 \(c_i\)

现在按顺序遍历每个操作,每个操作可执行可不执行。

最大化序列的颜色段数,即 \(1+\sum\limits_{i=2}^n[a_{i-1}\not=a_i]\)

\(1\leq a_i,c_i\leq n\leq\sum n\leq3\times10^5,1\leq m\leq\sum m\leq3\times10^5\)

\(\forall 1\leq i<j\leq n,[l_j,r_j]\nsubseteq [l_i,r_i]\)

首先,设 \(f_n\) 表示只考虑前 \(i\) 项且第 \(i\) 项保留原本值时最大颜色段数。

\(a_0=a_{n+1}=0\),答案就是 \(f_{n+1}-1\)

有转移方程 \(f_{i}=\max\{f_{i-1}+[a_i\not=a_{i-1}],\max\limits_{0\leq j<i-1}\{f_j+\text{maxcolor}(j,i)\}\}\)

其中 \(\text{maxcolor}(j,i)\) 表示当 \(a_j,a_i\) 都保留原本值时 \([j+1,i]\) 贡献的颜色段数的最大值。

显然 \(\text{maxcolor}(j,i)\) 并不能直接用式子表示。

\(g_i\) 表示第 \(i\) 个操作执行且 \(a_{r_i}\) 最终被第 \(i\) 次操作覆盖时 \([1,r_i]\) 的最大颜色段数。

更新我们的转移方程:

\(f_i=\max\{f_{i-1}+[a_i\not=a_{i-1}],\max\limits_{r_j=i-1}\{g_j+[c_j\not=a_i]\}\}\)

\(g_i=\max\{f_{l_i-1}+[c_i\not=a_{l_i-1}],\max\limits_{0\leq j<i,l_j\leq l_i-1\leq r_j\leq r_i}\{g_j+[c_j\not=c_i]\},\max\limits_{i<j\leq m,r_j<r_i}\{g_j+[c_j\not=c_i]\}\}\)

使用线段树优化即可做到 \(O(n+m\log m)\)

#include<bits/stdc++.h>
using namespace std;
const int MAXN=300005,inf=1e9;
const pair<int,int> Inf=make_pair(-inf,-1);
inline int read() {
	static int x=0,c=getchar(),f=1;
	for(f=1; c<=47||c>=58; c=getchar())f=f&&(c^45);
	for(x=0; c>=48&&c<=57; c=getchar())x=(x<<3)+(x<<1)+(c&15);
	return f?x:-x;
}
struct node {
	pair<int,int>a,b;
	inline node(pair<int,int>A=Inf,pair<int,int>B=Inf) {
		a=A,b=B;
	}
};
inline node Merge(node x,node y) {
	static node z;
	z.a=max(x.a,y.a),z.b=Inf;
	if(x.a.second!=z.a.second) z.b=x.a;
	if(y.a.second!=z.a.second) z.b=max(z.b,y.a);
	if(x.b.second!=z.a.second) z.b=max(z.b,x.b);
	if(y.b.second!=z.a.second) z.b=max(z.b,y.b);
	return z;
}
struct Tree {
	node val,tg;
} tr[MAXN<<2];
void build(int num,int l,int r) {
	tr[num].val=tr[num].tg=node();
	if(l==r)return;
	build(num<<1,l,(l+r)>>1),build(num<<1|1,(l+r+2)>>1,r);
}
inline void Tag(int num,node x) {
	if(~x.a.second) {
		tr[num].tg=Merge(tr[num].tg,x);
		static node p;
		p=tr[num].val;
		if(~p.a.second) {
			tr[num].val=Merge(tr[num].val,node(make_pair(x.a.first+(x.a.second!=p.a.second),p.a.second)));
			if(~x.b.second)
				tr[num].val=Merge(tr[num].val,node(make_pair(x.b.first+(x.b.second!=p.a.second),p.a.second)));
			if(~p.b.second) {
				tr[num].val=Merge(tr[num].val,node(make_pair(x.a.first+(x.a.second!=p.b.second),p.b.second)));
				if(~x.b.second)
					tr[num].val=Merge(tr[num].val,node(make_pair(x.b.first+(x.b.second!=p.b.second),p.b.second)));
			}
		}
	}
}
void push_down(int num) {
	if(~tr[num].tg.a.second) {
		Tag(num<<1,tr[num].tg);
		Tag(num<<1|1,tr[num].tg);
		tr[num].tg=node();
	}
}
void upd(int num,int l,int r,int x,node v) {
	if(l==r) {
		tr[num].val=v;
		return;
	}
	push_down(num);
	int mid=(l+r)>>1;
	if(x<=mid)upd(num<<1,l,mid,x,v);
	else upd(num<<1|1,mid+1,r,x,v);
	tr[num].val=Merge(tr[num<<1].val,tr[num<<1|1].val);
}
void update(int num,int l,int r,int L,int R,node x) {
	if(L>R)return;
	if(L<=l&&r<=R) return Tag(num,x);
	push_down(num);
	int mid=(l+r)>>1;
	if(L<=mid) update(num<<1,l,mid,L,R,x);
	if(mid<R)update(num<<1|1,mid+1,r,L,R,x);
	tr[num].val=Merge(tr[num<<1].val,tr[num<<1|1].val);
}
node query(int num,int l,int r,int L,int R) {
	if(L>R)return Inf;
	if(L<=l&&r<=R)return tr[num].val;
	push_down(num);
	int mid=(l+r)>>1;
	if(R<=mid) return query(num<<1,l,mid,L,R);
	if(mid<L)return query(num<<1|1,mid+1,r,L,R);
	return Merge(query(num<<1,l,mid,L,mid),query(num<<1|1,mid+1,r,mid+1,R));
}
int n,m,a[MAXN],col[MAXN],f[MAXN];
vector<int>add[MAXN],del[MAXN];
vector<node>vec;
inline void solve() {
	n=read(),m=read(),a[n+1]=0;
	for(int i=1; i<=n; ++i)a[i]=read();
	for(int i=1; i<=m; ++i) {
		add[read()].push_back(i);
		del[read()+1].push_back(i);
		col[i]=read();
	}
	build(1,1,m);
	for(int i=1; i<=n+1; ++i) {
		f[i]=f[i-1]+(a[i]!=a[i-1]);
		vec.clear();
		for(int x:add[i])vec.push_back(query(1,1,m,1,x-1));
		for(int x:add[i])upd(1,1,m,x,node(make_pair(-inf,col[x])));
		for(unsigned j=0; j<vec.size(); ++j)
			update(1,1,m,add[i][j],add[i][j],Merge(node(make_pair(f[i-1],a[i-1])),vec[j]));
		vec.clear();
		for(int x:del[i]) {
			vec.push_back(query(1,1,m,x,x));
			f[i]=max(f[i],vec.back().a.first+(col[x]!=a[i]));
			upd(1,1,m,x,node());
		}
		for(unsigned j=0; j<vec.size(); ++j)
			update(1,1,m,1,del[i][j],node(vec[j].a));
		add[i].clear(),add[i].shrink_to_fit();
		del[i].clear(),del[i].shrink_to_fit();
	}
	printf("%d\n",f[n+1]-1);
}
int main() {
	int t=read();
	while(t--)solve();
	return 0;
}
posted @ 2025-09-19 10:08  mod998244353  阅读(49)  评论(0)    收藏  举报
Live2D