此题解仅用于搞笑。
题解
这道题目被我们各种题意转换之后就是一个二维数点,带修改的。
由于我 ( ext{cdq}) 不太熟练,不知道带修改的该怎么搞,树套树的空间又被卡了(好像有人过了,反正我过不了),然后就决定学习一下 ( ext{KD-Tree}) 来搞二维数点。
然后我就写了一棵 ( ext{KD-Tree}) ,交了几发才过,很快啊,比树套树快。
代码
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5,K=2;
const int INF=1e9+7;
const double alpha=0.83;
int n,m,a[N],lst[N];
set<int> bag[N];
struct Point{int x[K];long long val;}p[N*7];
int cmp_data;
bool cmp(Point a,Point b){
if(a.x[cmp_data]!=b.x[cmp_data])
return a.x[cmp_data]<b.x[cmp_data];
return false;
}
struct KD_Tree{
int rt,tot,top,rub[N*7];
struct Node{
int ls,rs,size;long long sum;Point p;
int div,minn[K],maxn[K];
}tr[N*7];
KD_Tree(){
for(int i=0;i<K;++i) tr[0].minn[i]=INF;
for(int i=0;i<K;++i) tr[0].maxn[i]=-INF;
}
int newnode(){
if(top) return rub[top--];
return ++tot;
}
void recycle(int u){
tr[u]=tr[0],rub[++top]=u;
}
void up(int u){
tr[u].size=tr[tr[u].ls].size+tr[tr[u].rs].size+1;
tr[u].sum=tr[tr[u].ls].sum+tr[tr[u].rs].sum+tr[u].p.val;
for(int i=0;i<K;++i) tr[u].minn[i]=tr[u].maxn[i]=tr[u].p.x[i];
for(int i=0;i<K;++i){
tr[u].minn[i]=min(tr[u].minn[i],tr[tr[u].ls].minn[i]);
tr[u].minn[i]=min(tr[u].minn[i],tr[tr[u].rs].minn[i]);
tr[u].maxn[i]=max(tr[u].maxn[i],tr[tr[u].ls].maxn[i]);
tr[u].maxn[i]=max(tr[u].maxn[i],tr[tr[u].rs].maxn[i]);
}
}
int build(int l,int r,Point p[]){
if(l>r) return 0;
int u=newnode(),mid=(l+r)>>1;
tr[u].div=rand()%2,cmp_data=tr[u].div,nth_element(p+l,p+mid,p+r+1,cmp),tr[u].p=p[mid];
tr[u].ls=build(l,mid-1,p),tr[u].rs=build(mid+1,r,p);
return up(u),u;
}
bool check(int u){
return alpha*tr[u].size<=max(tr[tr[u].ls].size,tr[tr[u].rs].size);
}
void dfs(int u,int &cnt){
if(!u) return ;
dfs(tr[u].ls,cnt),dfs(tr[u].rs,cnt);
p[++cnt]=tr[u].p,recycle(u);
}
void rebuild(int &u){
int cnt=0;dfs(u,cnt),u=build(1,cnt,p);
}
void insert(int &u,Point p){
if(!u) return u=newnode(),tr[u].p=p,up(u);
if(p.x[tr[u].div]<=tr[u].p.x[tr[u].div])
insert(tr[u].ls,p);else insert(tr[u].rs,p);
if(check(u)) rebuild(u);
return up(u);
}
long long query(int u,int xl[],int xr[]){
if(!u) return 0;
for(int i=0;i<K;++i) if(tr[u].minn[i]>xr[i]||tr[u].maxn[i]<xl[i]) return 0;
int flag1=1,flag2=1;
for(int i=0;i<K;++i) flag1&=(xl[i]<=tr[u].minn[i]&&tr[u].maxn[i]<=xr[i]);
if(flag1) return tr[u].sum;
for(int i=0;i<K;++i) flag2&=(xl[i]<=tr[u].p.x[i]&&tr[u].p.x[i]<=xr[i]);
return flag2*tr[u].p.val+query(tr[u].ls,xl,xr)+query(tr[u].rs,xl,xr);
}
}t;
int main(){
srand(time(NULL));
cin>>n>>m;
for(int i=1;i<=n;++i){
Point p;
scanf("%d",&a[i]),bag[a[i]].insert(i);
set<int>::iterator tmp=bag[a[i]].find(i);
if(tmp!=bag[a[i]].begin())
p.x[1]=*tmp,tmp--,lst[i]=p.x[0]=*tmp;
else p.x[1]=*tmp,lst[i]=p.x[0]=0;
p.val=p.x[1]-p.x[0],t.insert(t.rt,p);
}
for(int i=1;i<=m;++i){
int opt,x,y;
scanf("%d%d%d",&opt,&x,&y);
if(opt==2){
int xl[K],xr[K];
xl[0]=xl[1]=x,xr[0]=xr[1]=y;
printf("%lld
",t.query(1,xl,xr));
}
else{
Point p;set<int>::iterator tmp;
tmp=bag[a[x]].find(x);
if(tmp!=bag[a[x]].end()){
p.x[0]=lst[*tmp],p.x[1]=*tmp;
p.val=p.x[0]-p.x[1],t.insert(t.rt,p);
}
tmp=bag[a[x]].upper_bound(x);
if(tmp!=bag[a[x]].end()){
p.x[0]=lst[*tmp],p.x[1]=*tmp;
p.val=p.x[0]-p.x[1],t.insert(t.rt,p);
}
tmp=bag[y].upper_bound(x);
if(tmp!=bag[y].end()){
p.x[0]=lst[*tmp],p.x[1]=*tmp;
p.val=p.x[0]-p.x[1],t.insert(t.rt,p);
}
bag[a[x]].erase(bag[a[x]].find(x)),bag[y].insert(x);
tmp=bag[y].find(x);
if(tmp!=bag[y].end()){
int fuck=*tmp;
if(tmp!=bag[y].begin())
p.x[1]=*tmp,tmp--,lst[fuck]=p.x[0]=*tmp;
else p.x[1]=*tmp,lst[fuck]=p.x[0]=0;
p.val=p.x[1]-p.x[0],t.insert(t.rt,p);
}
tmp=bag[y].upper_bound(x);
if(tmp!=bag[y].end()){
int fuck=*tmp;
if(tmp!=bag[y].begin())
p.x[1]=*tmp,tmp--,lst[fuck]=p.x[0]=*tmp;
else p.x[1]=*tmp,lst[fuck]=p.x[0]=0;
p.val=p.x[1]-p.x[0],t.insert(t.rt,p);
}
tmp=bag[a[x]].upper_bound(x);
if(tmp!=bag[a[x]].end()){
int fuck=*tmp;
if(tmp!=bag[a[x]].begin())
p.x[1]=*tmp,tmp--,lst[fuck]=p.x[0]=*tmp;
else p.x[1]=*tmp,lst[fuck]=p.x[0]=0;
p.val=p.x[1]-p.x[0],t.insert(t.rt,p);
}
a[x]=y;
}
}
return 0;
}