题解:CF1969E Unique Array
本篇题解提供一种扫描线的角度,但实质上与维护区间最小值的做法相近。
P5490 【模板】扫描线 & 矩形面积并
思路
首先,以
接着,由题意,对于序列中的一个下标
(如序列
显然,将每个
考虑扫描线求面积并的过程,设在
然后贪心处理,把
::::success[关于贪心的正确性]
对于一个未被覆盖的小正方形或其对应的非独特子段区间
下图为序列
不过图中还可以看出来本题有一些特殊性质,虽然不知道有什么用
::::
代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN=3e5+10;
int T,n,ans,a[MAXN],last[MAXN],l[MAXN];
int cov[MAXN*4],sum[MAXN*4];//cov: 线段树维护的区间被完整覆盖的次数 sum: 被覆盖过的长度和
void upd(int L,int R,int k,int i,int l,int r){
int mid=(l+r)>>1;
if(l==L&&R==r) cov[i]+=k;
else{
if(L<=mid) upd(L,min(R,mid),k,i*2,l,mid);
if(R>mid) upd(max(L,mid+1),R,k,i*2+1,mid+1,r);
}
if(cov[i]>0) sum[i]=r-l+1;
else if(l<r) sum[i]=sum[i*2]+sum[i*2+1];
else sum[i]=0;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--){
cin>>n;
ans=0,memset(last,0,sizeof(last[0])*(n+5)),memset(l,0,sizeof(l[0])*(n+5));
memset(cov,0,sizeof(cov[0])*(n+5)*4),memset(sum,0,sizeof(sum[0])*(n+5)*4);
for(int i=1;i<=n;i++){
cin>>a[i];
l[i]=last[a[i]]+1;
upd(l[i],i,1,1,1,n); //无需排序的在线扫描线(
if(last[a[i]]) upd(l[last[a[i]]],last[a[i]],-1,1,1,n);
if(sum[1]<i) ans++,upd(1,i,1,1,1,n); //发现右端点为i的非独特子段。
last[a[i]]=i; //维护a[i]上一次的出现位置
}
cout<<ans<<"\n";
}
return 0;
}