小米icpc邀请赛第一场 E
作者:互联网
题目意思:对于给定的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(int i,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; }
标签:return,vmi,int,icpc,第一场,区间,邀请赛,change,nw 来源: https://www.cnblogs.com/softmountain/p/13916451.html