小米icpc邀請賽第一場 E
阿新 • • 發佈:2020-11-03
題目意思:對於給定的i,i從1到m,需要找到含有1~i全部數字的最小區間長度,其實就是求mex。
我們可以維護這樣一個W[l][i],表示以l作為左端點滿足要求的最短區間的r的位置,那麼當我們計算i+1是,設i+1出現位置的序列為p,那麼我們對任意一個l處在兩個區間(p[k],p[k+1])內w[l[[i],可以得到w[l][i+1]=max{w[l][i],p[i+1][k+1]},從而完成轉移,注意對於最後一段,要全部賦值為無窮,這樣子就可以把問題變成區間賦值問題
#include<bits/stdc++.h> using namespace std; const int N=2e5+10; struct node { int l,r,laz,vmi,vr; }t[N<<2]; int n,x,m; vector<int> v[N]; void pushdown(int i) { if (!t[i].laz) return; t[i<<1].vmi=t[i].laz-t[i<<1].r; t[i<<1].vr=t[i<<1].laz=t[i].laz; t[i<<1|1].vmi=t[i].laz-t[i<<1|1].r; t[i<<1|1].vr=t[i<<1|1].laz=t[i].laz; t[i].laz=0; } void build(int i,int l,int r) { t[i].l=l,t[i].r=r,t[i].vmi=t[i].laz=0; if (l==r) {t[i].vr=l,t[i].vmi=0; return;} int mid=(l+r)>>1; build(i<<1,l,mid),build(i<<1|1,mid+1,r); t[i].vr=t[i<<1|1].vr; } void change(inti,int l,int r,int v) { if (t[i].l==l&&t[i].r==r) { t[i].laz=t[i].vr=v; t[i].vmi=v-t[i].r; return; } pushdown(i); int mid=(t[i].l+t[i].r)>>1; if (r<=mid) change(i<<1,l,r,v); else if (l>mid) change(i<<1|1,l,r,v); else change(i<<1,l,mid,v),change(i<<1|1,mid+1,r,v); t[i].vr=t[i<<1|1].vr; t[i].vmi=min(t[i<<1].vmi,t[i<<1|1].vmi); } int find(int i,int v) { if (t[i].l==t[i].r) { if (t[i].vr<=v) return t[i].l; else return t[i].l-1; } pushdown(i); int mid=(t[i].l+t[i].r)>>1; if (t[i<<1].vr<=v) return find(i<<1|1,v); return find(i<<1,v); } int main() { scanf("%d%d",&n,&m); for (int i=1; i<=m; i++) v[i].push_back(0); for (int i=1; i<=n; i++) scanf("%d",&x),v[x].push_back(i); build(1,1,n); for (int i=1; i<=m; i++) { int sz=v[i].size(); if (v[i][sz-1]<n) change(1,v[i][sz-1]+1,n,1000000000); for (int j=sz-1; j>=0; j--) { int nw=find(1,v[i][j]); if (nw>v[i][j-1]&&j) change(1,v[i][j-1]+1,nw,v[i][j]); } printf("%d%c",t[1].vmi+1,i==m?'\n':' '); } return 0; }