解题思路
我们设
p
r
e
i
pre_i
prei表示,
i
i
i这个位置上一个出现相同数字的位置,
v
a
l
i
val_i
vali表示
i
−
p
r
e
i
i-pre_i
i−prei
那我们发现
v
a
l
i
+
v
a
l
p
r
e
i
=
i
−
p
r
e
i
+
p
r
e
i
−
p
r
e
p
r
e
i
=
i
−
p
r
e
p
r
e
i
val_i+val_{pre_i}=i-pre_i+pre_i-pre_{pre_i}=i-pre_{pre_i}
vali+valprei=i−prei+prei−preprei=i−preprei
正好是第一次和最后一次出现位置的位置差,也就是题目求的值
所以我们实际上试求
∑
i
,
i
≤
r
,
p
r
e
i
≥
l
v
a
l
i
\sum_{i,i\leq r,pre_i\geq l}val_i
∑i,i≤r,prei≥lvali
这是一个二维偏序的形式,直接用CDQ分治求出来
对于修改操作,可以把原来的贡献减掉,新的贡献加上
可以对每个数字开个set维护位置
因为有了时间顺序,所以实际是
∑
i
,
i
≤
r
,
p
r
e
i
≥
l
,
t
i
<
j
v
a
l
i
\sum_{i,i\leq r,pre_i\geq l,t_i<j}val_i
i,i≤r,prei≥l,ti<j∑vali
其中
j
j
j是当前操作的时间,
t
i
t_i
ti是第
i
i
i操作的时间
#include<bits/stdc++.h>
using namespace std;
const int N = 6e5+7;
typedef long long LL;
const int INF = 1e9+7;
struct node
{
int x,y,t,v,id,tp;
}q[3*N],tmp[2*N];
int tot=0;
LL ans[N];
LL tree[N];
bool cmp(node a,node b)
{
if(a.x!=b.x) return a.x<b.x;
if(a.y!=b.y) return a.y<b.y;
if(a.t!=b.t) return a.t<b.t;
return a.tp>b.tp;
}
void Add(int x,int y,int t,int v,int id,int tp)
{
tot++;
q[tot].x=x;
q[tot].y=y;
q[tot].t=t;
q[tot].v=v;
q[tot].id=id;
q[tot].tp=tp;
}
void add(int x,LL v)
{
for(int i=x;i<=tot;i+=(i&-i))
tree[i]+=v;
}
LL ask(int x)
{
LL res=0;
for(int i=x;i;i-=(i&-i))
res+=tree[i];
return res;
}
void CDQ(int l,int r)
{
if(l>=r) return;
int mid=(l+r)>>1;
CDQ(l,mid);
CDQ(mid+1,r);
int i=l,j=mid+1,top=0;
while(i<=mid&&j<=r)
{
if(q[i].y<=q[j].y)
{
if(q[i].tp==1) add(q[i].t,q[i].v);
tmp[++top]=q[i++];
}
else
{
if(q[j].tp==0) ans[q[j].id]+=ask(q[j].t-1);
tmp[++top]=q[j++];
}
}
while(i<=mid)
{
if(q[i].tp==1) add(q[i].t,q[i].v);
tmp[++top]=q[i++];
}
while(j<=r)
{
if(q[j].tp==0) ans[q[j].id]+=ask(q[j].t-1);
tmp[++top]=q[j++];
}
for(int k=l;k<=mid;k++)
if(q[k].tp==1) add(q[k].t,-q[k].v);
for(int k=1;k<=top;k++)
q[l+k-1]=tmp[k];
}
set<int> col[N];
set<int>::iterator it,p;
int n,m;
int c[N];
vector<int> seq;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%d",&c[i]);
int pre=0;
if(col[c[i]].size())
{
it=col[c[i]].end();
it--;
pre=(*it);
}
col[c[i]].insert(i);
Add(i,pre?-pre:-INF,1,pre?(i-pre):0,0,1);
}
for(int i=1;i<=m;i++)
{
int t,a,b;
scanf("%d %d %d",&t,&a,&b);
if(t==1)
{
int pre=0,nxt=0;
it=col[c[a]].find(a);
p=it;
if(it==col[c[a]].begin()) pre=0;
else
{
it--;
pre=(*it);
it++;
}
Add(a,pre?-pre:-INF,i+1,pre?-(a-pre):0,0,1);
it++;
if(it==col[c[a]].end()) nxt=-1;
else nxt=a;
if(nxt!=-1)
{
Add(*it,-nxt,i+1,-((*it)-nxt),0,1);
Add(*it,pre?-pre:-INF,i+1,pre?(*it)-pre:0,0,1);
}
col[c[a]].erase(p);
c[a]=b;
col[c[a]].insert(a);
it=col[c[a]].find(a);
p=it;
if(it==col[c[a]].begin()) pre=0;
else
{
it--;
pre=(*it);
it++;
}
Add(a,pre?-pre:-INF,i+1,pre?a-pre:0,0,1);
it++;
if(it==col[c[a]].end()) nxt=-1;
else nxt=a;
if(nxt!=-1)
{
Add(*it,pre?-pre:-INF,i+1,pre?-((*it)-pre):0,0,1);
Add(*it,-nxt,i+1,(*it)-nxt,0,1);
}
}
else
{
Add(b,-a,i+1,0,i,0);
seq.push_back(i);
}
}
sort(q+1,q+tot+1,cmp);
CDQ(1,tot);
for(int i=0;i<seq.size();i++)
{
int x=seq[i];
printf("%lld\n",ans[x]);
}
return 0;
}
/*
7 3
1 2 3 1 3 2 1
1 7 2
1 3 2
2 1 6
*/