数组
Description
给出一个长度为
n
的序列,每个位置上都有一种颜色。
我们称一个区间是合法的当且仅当该区间内没有两个颜色相同的位置。
接着给出
1、修改:每次可以修改一个位置的颜色。
2、询问:询问整个序列内有多少个合法的子区间。
Data Constraint
n
<=
Solution
第一次用线段树维护单调栈,猎奇操作。
设
那我们设
sufi
=
max
(
lastj
)(
j
<=
那么答案显然为
n∗(n+1)2
-
∑ni=1sufi
。
关于 lasti 的实时维护,我们可以对每一种颜色开一个 set ,考虑到一个点颜色的变化最多只会影响到三个点的 last 值的变化,这些位置都可以在 set 中用 lower _ bound 快速找到。
接下来考虑如何求 sufi ,我们可以从左往右做同时维护一个单调栈,做到i时的栈顶高度就是 sufi 。
接下来考虑用线段树维护单调栈。
给出函数
query
(
l
,
那显然有答案为
query
(
1
,
接着考虑如何求
倘若我们要求
query
(
l
,
1、若
lx
<=
high
,则返回(
mid
-
l
+
2、若
lx
>
high
,则返回
query
(
l
,
我们发现
query
(
mid
+
1
,
由于每次修改会影响
log2
n
个节点,每一个节点都需要
而执行
其实这种做法可以理解成把整个序列分成被
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#pragma GCC optimize(3)
#define fo(i,j,l) for(int i=j;i<=l;++i)
#define fd(i,j,l) for(int i=j;i>=l;--i)
using namespace std;
typedef long long ll;
const ll N=12e4,M=4*N;
set<int> color[N];
int last[N],used[N],ys[N];
ll keep[M],zd[M];
int x,y,n,q,i,j,k,l,o;
inline ll max(ll a,ll b)
{return a>b?a:b;}
ll query(int o,int l,int r,ll op)
{
if(l==r)return max(op,last[l]);
int mid=l+r>>1;
if(zd[o*2]<=op)return (mid-l+1)*op+query(o*2+1,mid+1,r,op);
else return query(o*2,l,mid,op)+keep[o*2+1];
}
void build(int o,int l,int r)
{
if(l==r){
zd[o]=last[l];
return;
}
int mid=l+r>>1;
build(o*2,l,mid); build(o*2+1,mid+1,r);
zd[o]=max(zd[o*2],zd[o*2+1]);
keep[o*2+1]=query(o*2+1,mid+1,r,zd[o*2]);
}
void change(int o,int l,int r,int op,int yu)
{
if(l==r){
last[l]=zd[o]=yu;
return ;
}
int mid=l+r>>1;
if(op<=mid)change(o*2,l,mid,op,yu);
else change(o*2+1,mid+1,r,op,yu);
zd[o]=max(zd[o*2],zd[o*2+1]);
keep[o*2+1]=query(o*2+1,mid+1,r,zd[o*2]);
}
int main()
{
cin>>n;
fo(i,1,n)color[i].clear();
fo(i,1,n)color[i].insert(0),color[i].insert(n+1);
fo(i,1,n){
scanf("%d",&x); ys[i]=x;
color[x].insert(i);
last[i]=used[x]; used[x]=i;
}
build(1,1,n);
cin>>q; ll ans=(ll)n*(n+1)>>1;
fo(i,1,q){
scanf("%d",&x);
if(x==0)printf("%lld\n",ans-query(1,1,n,0));
else{
scanf("%d%d",&x,&y);
if(ys[x]==y)continue;
int wz=*color[ys[x]].lower_bound(x+1);
if(wz<=n){
int w1=*(--color[ys[x]].lower_bound(x));
change(1,1,n,wz,w1);
}
color[ys[x]].erase(x);
ys[x]=y;
int w2=*(--color[y].lower_bound(x));
int w3=*color[y].lower_bound(x);
color[y].insert(x);
change(1,1,n,x,w2);
if(w3!=n+1)change(1,1,n,w3,x);
}
}
}