[線段樹] Codeforces 1436E Complicated Computations
阿新 • • 發佈:2020-11-16
題目大意
給定一個長為 \(n(n\leq 10^5)\) 的數列 \(\{a_n\}\),其中每個數 \(a_i\) 都在 \(1\sim n\) 之中。求這個數列所有連續子數列的\(\mathrm{mex}\)值的 \(\mathrm{mex}\)。
題解
想了好久,想了個巨難寫的做法,太菜了。
首先把數列中的所有數從小到大排序,相同的數按下標從小到大排序。然後我們按 \(1\sim n\) 列舉 \(x\),看 \(x\) 是否能成為子數列 \(\mathrm{mex}\) 值的 \(\mathrm{mex}\),即是否存在某個連續子陣列的 \(\mathrm{mex}\) 是 \(x\)
考慮怎麼判斷是否存在某個連續子陣列的 \(\mathrm{mex}\) 是 \(x\),不妨把原陣列中的 \(x\) 全部刪去,原陣列就分成若干段,若其中某一段存在 \(1\sim x-1\) 中的所有數,則該段的 \(\mathrm{mex}\) 是 \(x\)。我們可以維護兩個支援區間加的樹狀陣列 \(\mathrm{Left}\) 和 \(\mathrm{Right}\),\(\mathrm{Left}\) 維護每一個位置上的數所處段的左端點,\(\mathrm{Right}\)
但是這樣非常難寫,其實有更好的做法。
建立一棵線段樹,我們直接從左到右掃一遍原陣列,當掃描到 \(a_m\) 時,線段樹上第 \(i\) 個位置維護 \(a_1\sim a_{m-1}\) 中等於 \(i\) 的數最後一次出現的位置,設 \(x\) 為線段樹上 \(1\sim a_{m-1}\) 中的最小值,即最後出現的位置最早的數的位置,若 \(x\)
Code
#include <bits/stdc++.h>
using namespace std;
#define RG register int
#define LL long long
template<typename elemType>
inline void Read(elemType &T){
elemType X=0,w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
T=(w?-X:X);
}
const int maxn=100010;
struct SegmentTree{
int T[maxn<<2];
void Update(int Root,int L,int R,int pos,int val){
if(L==R){T[Root]=val;return;}
int mid=(L+R)>>1;
if(pos<=mid) Update(Root<<1,L,mid,pos,val);
else Update(Root<<1|1,mid+1,R,pos,val);
T[Root]=min(T[Root<<1],T[Root<<1|1]);
}
int Query(int Root,int L,int R,int QL,int QR){
if(QR<L || R<QL) return 1<<30;
if(QL<=L && R<=QR) return T[Root];
int mid=(L+R)>>1;
return min(Query(Root<<1,L,mid,QL,QR),Query(Root<<1|1,mid+1,R,QL,QR));
}
};
SegmentTree Tree;
int data[maxn];
bool mex[maxn];
int N;
int main(){
Read(N);
bool flag=true;
for(int i=1;i<=N;++i){
Read(data[i]);
if(data[i]!=1) flag=false;
}
if(flag){printf("1\n");return 0;}
mex[1]=true;
for(int i=1;i<=N;++i){
if(data[i]==1){Tree.Update(1,1,N+1,data[i],i);continue;}
if(Tree.Query(1,1,N+1,1,data[i]-1)>Tree.Query(1,1,N+1,data[i],data[i])) mex[data[i]]=true;
Tree.Update(1,1,N+1,data[i],i);
}
for(int i=2;i<=N+1;++i)
if(Tree.Query(1,1,N+1,1,i-1)>Tree.Query(1,1,N+1,i,i)) mex[i]=true;
for(int i=1;i<=N+2;++i)
if(!mex[i]){printf("%d\n",i);break;}
return 0;
}