AT_jsc2019_final_h Distinct Integers

题意:给一个长度为 \(n(n\le 5\times 10^5)\) 的数组 \(a\) ,两个操作:

  • \(0\) \(x\) \(y\) 将 $a_x $ 修改成 \(y\)

  • \(1\) \(l\) \(r\) 查询 \([l,r]\) 有多少子区间满足区间内元素两两不相等

先简化问题,求 \([1,n]\) 有多少子区间满足条件,设 \(pre_i=\) 上一个与 \(a_i\) 相等的数,答案就是 \(n*(n+1)/2-\) \(\sum^n_{i=1} \max\{pre_{j,{j\le i}}\}\) 对于 \(pre\) ,使用 \(set\) 维护,所以这个题就变成了维护前缀最大值!参照楼房重建 ,维护两个值,区间内前缀最大值的和(\(sum\)),区间内的前缀最大值的最大值(\(x\)),于是搞一个线段树二分,求的是区间内的\(\sum \max\{v,\) 前缀最大值 \(\}\),这样合并两个区间时,就可以 \(mx_p=\max\{mx_{ls},mx_{rs}\}\) \(sum_p=sum_{ls}+query(rs的区间,mx_{ls})\) ,因为查答案查的不是全局的,所以再弄个函数,把 \([l,r]\) 在线段树上的节点分割出来

code:

#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
#pragma GCC optimeze(3)
#pragma GCC optimeze(2)
#define PII pair<int, int>
#define pb push_back
#define fi first
#define se second
#define lowbit(x) (x & (-x))
#define inv(x) (qpow(x,mod-2))
#define blong(i) ((i+K-1)/K)
using namespace std;
const int N=5e5+10;
int n,m,a[N],sum[N<<2],mx[N<<2],v[N];
set<int>s[N];
int qu(int p,int l,int r,int v){//查询区间内max(v,前缀最大值)之和 
   if(l==r)return max(v,mx[p]);
   int mid=(l+r)>>1;
   if(mx[p<<1]<v)return v*(mid-l+1)+qu(p<<1|1,mid+1,r,v);
   return sum[p]-sum[p<<1]+qu(p<<1,l,mid,v);
}
void pushup(int p,int l,int r){
   int mid=(l+r)>>1;
   mx[p]=max(mx[p<<1],mx[p<<1|1]);
   sum[p]=sum[p<<1]+qu(p<<1|1,mid+1,r,mx[p<<1]);
}
void build(int p,int l,int r){
   if(l==r){
   	mx[p]=sum[p]=v[l];return;
   }
   int mid=(l+r)>>1;
   build(p<<1,l,mid);
   build(p<<1|1,mid+1,r);
   pushup(p,l,r);
}
void change(int x,int p,int s,int t,int k){
   if(s==t){
   	mx[p]=sum[p]=k;return;
   }
   int mid=(s+t)>>1;
   if(mid>=x)change(x,p<<1,s,mid,k);
   else change(x,p<<1|1,mid+1,t,k);
   pushup(p,s,t);
}
vector<int>P,S,T;
void getl(int l,int r,int p,int s,int t){//将[l,r]分割成线段树上的线段 
   if(s>=l&&t<=r){
   	P.pb(p),S.pb(s),T.pb(t);return;
   }
   int mid=(s+t)>>1;
   if(mid>=l)getl(l,r,p<<1,s,mid);
   if(mid<r)getl(l,r,p<<1|1,mid+1,t);
}
int query(int l,int r){
   P.clear(),S.clear(),T.clear();
   getl(l,r,1,1,n);
   int ans=0,pre=l-1;
   for(int i=0;i<P.size();i++){
   	ans+=qu(P[i],S[i],T[i],pre);
   	pre=max(pre,mx[P[i]]);
   } 
   return ans;
}
signed main(){ 
   ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
   cin>>n>>m;
   for(int i=1;i<=n;i++){
   	cin>>a[i];
   	if(s[a[i]].size()){
   		auto it=s[a[i]].end();
   		it--;
   		v[i]=(*it);
   	}
   	s[a[i]].insert(i);	
   }
   build(1,1,n);
   while(m--){
   	int opt,l,r;cin>>opt>>l>>r;
   	l++;
   	if(opt==0){
   		s[a[l]].erase(l);
   		auto it=s[a[l]].lower_bound(l);
   		if(it!=s[a[l]].end()){
   			if(it==s[a[l]].begin())change(*it,1,1,n,0);
   			else {
   				it--;
   				int x=*it;
   				it++;
   				change(*it,1,1,n,x);
   			}
   		}
   		a[l]=r;
   		s[r].insert(l);
   		it=s[r].lower_bound(l);
   		if(it==s[r].begin())change(l,1,1,n,0);
   		else{
   			it--;
   			int u=*it;
   			it++;
   			change(*it,1,1,n,u);
   		}
   		it++;
   		if(it!=s[r].end())change(*it,1,1,n,l);
   	}
   	else cout<<(l+r)*(r-l+1)/2-query(l,r)<<'\n';
   }
   return 0;
}
posted @ 2025-02-16 21:19  Xdik  阅读(54)  评论(0)    收藏  举报