CF1209G Into Blocks
一、题目
二、解法
开始反思了,为什么我总是不能达成有效的思考,是题目太难还是我根本没有静下心来??
考虑把原序列分成若干段,每一段都变成一个颜色。那么问题如何分段?我们知道如果某个颜色出现的区间是 ,那么这个区间一定是要在同一段内的,也就是任意 , 和 都是不能断开的。
那么我们可以把 都打上 的标记,对于最终值为 的位置,我们是可以在这个位置断开的,而且能断开则断开的策略一定是最优的。所以最后我们会获得若干段,答案就是 每一段内的最大值。
考虑用线段树维护所有断开的位置,我们原本想要在值为 的地方断开,这并不好维护。但是根据套路,我们可以在值为区间最小值的地方断开,这样到了根节点,因为最小值 ,所以就可以直接拿答案了。
那么我们维护 表示 代表区间内的覆盖次数最小值,设 表示中间被断点闭合的区间的最大值之和, 分别为左右还未闭合的区间的最大值, 表示区间最大值,讨论左右儿子 的关系就可以上传。
我们把每个颜色的出现次数放在它的第一个节点的位置,那么只需要支持单点修改和区间覆盖修改。至于颜色则可以拿个 来维护,时间复杂度
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
const int M = 200005;
const int N = M<<2;
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,q,a[M],mx[N],lc[N],rc[N],tg[N],mn[N],tr[N];
set<int> s[M];
void down(int i)
{
if(!tg[i]) return ;
tg[i<<1]+=tg[i];tg[i<<1|1]+=tg[i];
mn[i<<1]+=tg[i];mn[i<<1|1]+=tg[i];
tg[i]=0;
}
void up(int i)
{
int ls=i<<1,rs=i<<1|1;
if(mn[ls]<mn[rs])
{
tr[i]=tr[ls];lc[i]=lc[ls];
rc[i]=max(rc[ls],mx[rs]);
}
else if(mn[i<<1]>mn[i<<1|1])
{
tr[i]=tr[rs];rc[i]=rc[rs];
lc[i]=max(lc[rs],mx[ls]);
}
else
{
tr[i]=tr[ls]+tr[rs]+max(rc[ls],lc[rs]);
lc[i]=lc[ls];rc[i]=rc[rs];
}
mx[i]=max(mx[ls],mx[rs]);
mn[i]=min(mn[ls],mn[rs]);
}
void ins(int i,int l,int r,int id,int c)
{
if(l==r) {mx[i]=lc[i]=c;return ;}
int mid=(l+r)>>1;down(i);
if(mid>=id) ins(i<<1,l,mid,id,c);
else ins(i<<1|1,mid+1,r,id,c);
up(i);
}
void cov(int i,int l,int r,int L,int R,int c)
{
if(L>r || l>R) return ;
if(L<=l && r<=R) {tg[i]+=c;mn[i]+=c;return ;}
int mid=(l+r)>>1;down(i);
cov(i<<1,l,mid,L,R,c);
cov(i<<1|1,mid+1,r,L,R,c);
up(i);
}
void modify(int x,int c)
{
if(s[x].empty()) return ;
ins(1,1,n,*s[x].begin(),c>0?s[x].size():0);
cov(1,1,n,*s[x].begin(),*s[x].rbegin()-1,c);
}
signed main()
{
n=read();q=read();
for(int i=1;i<=n;i++)
a[i]=read(),s[a[i]].insert(i);
for(int i=1;i<=n;i++)
if(*s[a[i]].begin()==i) modify(a[i],1);
printf("%d\n",n-tr[1]-lc[1]-rc[1]);
while(q--)
{
int x=read(),y=read(),z=a[x];
modify(z,-1);s[z].erase(x);modify(z,1);
modify(y,-1);s[y].insert(x);modify(y,1);
printf("%d\n",n-tr[1]-lc[1]-rc[1]);a[x]=y;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)