题目
给定一个长为n(n<=2e5)的数组a[],再给一个阈值m(m<=n),
保证1<=ai<=m,且[1,m]的数每个都至少在数组中出现一次
对于每个i属于[1,m],询问区间内 值域的并集包含了[1,i]的所有数的 最短的连续区间是多长
思路来源
官方题解
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=45328431 北大逆十字队代码
题解
官方题解和北大逆十字队20min一血代码一模一样,就tm离谱
首先考虑的维护这个东西,再考虑后续优化,
每个位置维护当前端点往右的包含的最小右端点,
状态是的,但是只有
个数会带来更新,
如果能每次更新只有个状态,复杂度就降下来了
每次新加进来一个数的时候,对于
之间的数,
要么往右挪成
,要么本身的值就大于
,从而不变
注意到维护的这个东西显然单调,即,
这说明,之间存在一个分界点x,
是要往右挪成
的,这一段需要区间赋值成
而是保持不变的,这个分界点
可以线段树上二分求,
为了实现线段树二分,需要维护在非叶节点上维护的最大值,
从而用于二分的最小位置
而求答案时,则需用每个更新
的答案,
这就是,取个最小值
所以线段树内,再维护一个的最小值即可
代码
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
const int N=2e5+10;
int n,m,v;
vector<int>pos[N];
struct segtree{
int n;
//cov就是正常的区间赋值标记
//r(i,l)表示对于l来说凑齐[1,i]的最小右端点 滚掉第一维
//叶子结点的mxr即r(i,l)
//分支节点是所有叶子结点的max 用于线段树二分
//ans用于维护min(r(i,l)-l),此时+1即为答案
struct node{int l,r,cov,mxr,ans;}e[N<<2];
#define l(p) e[p].l
#define r(p) e[p].r
#define c(p) e[p].cov
#define m(p) e[p].mxr
#define a(p) e[p].ans
void up(int p){m(p)=max(m(p<<1),m(p<<1|1));a(p)=min(a(p<<1),a(p<<1|1));}
void bld(int p,int l,int r){
l(p)=l;r(p)=r;c(p)=0;
if(l==r){m(p)=l;a(p)=0;return;}//不妨假设最开始都只需要1的长度即可凑齐0
int mid=l+r>>1;
bld(p<<1,l,mid);bld(p<<1|1,mid+1,r);
up(p);
}
void psd(int p){
if(c(p)){
m(p<<1)=c(p<<1)=c(p);
a(p<<1)=m(p<<1)-r(p<<1);
m(p<<1|1)=c(p<<1|1)=c(p);
a(p<<1|1)=m(p<<1|1)-r(p<<1|1);
c(p)=0;
}
}
void init(int _n){n=_n;bld(1,1,n);}
void chg(int p,int ql,int qr,int v){
if(ql>qr)return;
if(ql<=l(p) && r(p)<=qr){
c(p)=m(p)=v;
a(p)=v-r(p);
return;
}
psd(p);
int mid=l(p)+r(p)>>1;
if(ql<=mid)chg(p<<1,ql,qr,v);
if(qr>mid)chg(p<<1|1,ql,qr,v);
up(p);
}
int find(int p,int v){//线段树二分>=v的最左位置
if(l(p)==r(p))return l(p);
psd(p);
int mid=l(p)+r(p)>>1;
if(m(p<<1)>=v)return find(p<<1,v);
return find(p<<1|1,v);
}
}seg;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i){
pos[i].pb(0);
}
for(int i=1;i<=n;++i){
scanf("%d",&v);
pos[v].pb(i);
}
seg.init(n);
for(int i=1;i<=m;++i){
int sz=pos[i].size();
if(pos[i][sz-1]+1<=n){
seg.chg(1,pos[i][sz-1]+1,n,1000000000);//凑不成 即INF
}
for(int j=sz-1;j>=1;--j){
int ub=seg.find(1,pos[i][j])-1;
seg.chg(1,pos[i][j-1]+1,ub,pos[i][j]);
}
printf("%d%c",seg.e[1].ans+1," \n"[i==m]);
}
return 0;
}