给一个数列,每次修改一个数字或者问有多少区间内没有相同的数字的区间。n,m≤105n,m\le10^5n,m≤105
题解:
首先固定r,相当于l不断变小同时pre的max变大,一直到要max(pre)>=l为止。
考虑类似线段树维护单调栈的做。
每次一个区间的答案等于左区间的答案加上,从右区间开始往左走并考虑左区间对右区间的影响。
考虑在线段树上二分出右区间最长的一个前缀,满足这个前缀的max(pre)<=左区间的max(pre),那么这段区间都等价于从从mid开始往左走(并且显然可以走到mid),对与后半部分,左区间对其没有影响(被这个前缀堵死了),直接用已经算好的东西更新答案即可。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<set>
#define N 100010
#define gc getchar()
#define lint long long
using namespace std;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
typedef set<int>::iterator sit;
struct segment{
int l,r,mx;lint ans;
segment *ch[2];
}*rt;set<int> s[N];int pre[N],a[N],h[N];
int cut_segment(segment* &rt,segment* &t,int lm)
{
int l=rt->l,r=rt->r;if(l==r) return t->ans+=l-max(lm,rt->mx),0;int mid=(l+r)>>1;
if(rt->ch[0]->mx<=lm)
t->ans+=(mid-l+1ll)*(l-1-lm)+(mid-l+1ll)*(mid-l+2ll)/2,cut_segment(rt->ch[1],t,lm);
else t->ans+=rt->ans-rt->ch[0]->ans,cut_segment(rt->ch[0],t,lm);return 0;
}
inline int push_up(segment* &rt)
{
int l=rt->l,r=rt->r,mid=(l+r)>>1,lm=rt->ch[0]->mx;
rt->mx=max(rt->ch[0]->mx,rt->ch[1]->mx),rt->ans=rt->ch[0]->ans;
if(rt->ch[0]->mx>=rt->ch[1]->mx) rt->ans+=((lint)mid-lm)*(r-mid)+(r-mid)*(r-mid+1ll)/2;
else cut_segment(rt->ch[1],rt,lm);return 0;
}
int build(segment* &rt,int l,int r)
{
rt=new segment,rt->l=l,rt->r=r;int mid=(l+r)>>1;
if(l==r) return rt->mx=pre[l],rt->ans=l-pre[l],0;
build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r);
return push_up(rt);
}
int update(segment* &rt,int p)
{
int l=rt->l,r=rt->r,mid=(l+r)>>1;
if(l==r) return rt->mx=pre[p],rt->ans=p-pre[p],0;
return update(rt->ch[p>mid],p),push_up(rt);
}
int main()
{
int n=inn();
for(int i=1;i<=n;i++) a[i]=inn();
for(int i=1;i<=n;i++) pre[i]=h[a[i]],h[a[i]]=i;
for(int i=1;i<=n;i++) s[a[i]].insert(i);
build(rt,1,n);
for(int q=inn(),opt;q;q--)
if(!(opt=inn())) printf("%lld\n",rt->ans);
else{
int x=inn(),v=inn();
set<int> &s1=s[a[x]],&s2=s[v];
sit it=s1.upper_bound(x),its;
if(it!=s1.end())
pre[*it]=pre[x],update(rt,*it);
s1.erase(x),a[x]=v,s2.insert(x);
its=it=s2.lower_bound(x),it++;
if(it!=s2.end()) pre[*it]=x,update(rt,*it);
if(its!=s2.begin()) its--,pre[x]=*its;
else pre[x]=0;update(rt,x);
}
return 0;
}