当前位置: 首页 > news >正文

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,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;
}
http://www.hskmm.com/?act=detail&tid=9397

相关文章:

  • 文件自动同步软件用哪个好,高效选择指南
  • 【初赛】指针 - Slayer
  • 国产化FPGA-2050-基于JFMK50T4(XC7A50T)的核心板
  • hbase学习2
  • 基于Python+Vue开发的健身房管理系统源码+运行步骤
  • 2025年纷享销客生态伙伴大会无锡站圆满举办!
  • 英语_阅读_digital technology_待读
  • 达梦 两个bug json 导致数据库crash 和 优化器解析or 导致结果不一样
  • MySQL迁移至GreatSQL后,timestamp字段插入报错解析
  • 2025年文件摆渡系统哪个品牌好推荐
  • Python中使用列表、map和filter函数配合lambda表达式来操作集合
  • 大模型decoder中权重矩阵的理解 - 实践
  • 文件安全外发平台用哪个,最佳选择是什么?
  • 【初赛】数 - Slayer
  • http连接(webFlux vs tomcat)
  • 英语_阅读_Generative AI_待读
  • P8500 [NOI2022] 冒泡排序 题解
  • 【初赛】链表 - Slayer
  • 纷享销客CRM系统自定义APL代码破解企业深度定制难题
  • 第2章 zynq开发板FSBL的生成和NAND烧录
  • 工具大全
  • RocketMQ vs kafka
  • JL-32 土壤速测仪 手持便携 大容量 多参数可同时监测
  • 直播录制神器!一款多平台直播流自动录制客户端!
  • 101.计组--二章
  • LobeChat搭建
  • 推荐几家国外的AI模型应用网站
  • 长园智能装备遇上利驰SuperHarness-3D,实现充电桩线束设计效率与精度双提升!
  • 学习笔记:操作分块 / 根号重构
  • url测试脚本2