百折不挠|

Xdik

园龄:1个月粉丝:7关注:24

AT_jsc2019_final_h Distinct Integers

题意:给一个长度为 n(n5×105) 的数组 a ,两个操作:

  • 0 x yax 修改成 y

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

先简化问题,求 [1,n] 有多少子区间满足条件,设 prei= 上一个与 ai 相等的数,答案就是 n(n+1)/2 i=1nmax{prej,ji} 对于 pre ,使用 set 维护,所以这个题就变成了维护前缀最大值!参照楼房重建 ,维护两个值,区间内前缀最大值的和(sum),区间内的前缀最大值的最大值(x),于是搞一个线段树二分,求的是区间内的max{v, 前缀最大值 },这样合并两个区间时,就可以 mxp=max{mxls,mxrs} sump=sumls+query(rs,mxls) ,因为查答案查的不是全局的,所以再弄个函数,把 [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;
}

本文作者:Xdik

本文链接:https://www.cnblogs.com/Xdik/p/18718805

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Xdik  阅读(10)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起