1 条题解
-
0
自动搬运
来自洛谷,原作者为

lsj2009
关关雎鸠,在河之洲搬运于
2025-08-24 22:53:29,当前版本为作者最后更新于2023-12-20 18:17:37,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
闲话
膜你赛刚做过类似的 trick,结果马上就用上了/jy
场上一下子就切了,没吃罚时,很爽!
Solution
结论
先说一个经典(?结论:
方便起见,先下一个定义:
我们称满足 的区间为 区间。
对于一个 区间 ,如果不存在另一个 区间 ,则称 为『极小的 mex 区间』。
-
则有结论:极小的 mex 区间只有 个;具体的,一个上界是 。
-
证明:对于一个满足条件的『极小的 mex 区间』 显然满足 ,否则删任意一个不影响答案,不妨假设 ,则 和 的加入先后影响了 的答案,则可以得到的是:,由于当 固定时 单调不降,且有多个满足他条件的 只取最左边那个,所以对于任意的 只有一个 满足条件;同理,对于 的情况,对于每个 也至多只有一个 满足条件,故最多只有 个『极小的 mex 区间』。
求『极小的 mex 区间』
然后我们考虑知道了这么一个性质只会要怎么做。
那么我们首先要把所有极小的 mex 区间给掏出来,这个好像说是有什么『阶梯状』的东西,和同学们讨论了一下,不是很懂(或者说感觉不是很好维护),这里讲一个比较脑瘫的求法。如果说你会比较优雅的求法,那么可以选择跳过。
假设我们已经求出 的答案,我们考虑如何推出 的答案。
那么一个比较显然的结论是: 的一个答案区间必然是往 的一个答案区间两边加上了 然后得到。
然后我们就得到了一个求『极小的 mex 区间』的算法:
- 预处理出极小的 和 区间。
- 对于每一个极小的 区间分别求出其距离左端点最近的 出现位置,和距离右端点最近的 出现位置,形成两个新的区间,算一下两个区间的 ,然后丢到对应的存储 区间的
vector里。 - 对于存储 区间的
vector求极小区间。
由于最终答案是 级别的,所以任何时刻的区间个数不会超过 级别,复杂度是 。
对于实现细节:
-
求在某个点左/右侧最近的 的点:开 个
vector,分别存储每个数的出现位置,vector上二分即可。 -
在线求区间 mex:这个也就是 P4137,主席树即可,不再赘述。
计算答案
我们考虑对于每个『极小的 区间』 求出其对应的『极大的 区间』。
则对于任意 的集合都可以拥有 这个数,我们考虑把区间 推平成 。
然后对于最终为 的点显然 mex 不大于 。
则我们倒着枚举 ,每次将其为 的点在答案序列上位置修改成 ,最终即为答案。
至于区间推平,ODT 即可。
需要注意的是,这里 ODT 复杂度不依赖于随机,而依赖于均摊。
具体的,每次未被推平成 的节点构成了若干个区间,区间总数至多为 个( 表示『极小的 区间』个数),由于 ,所以总共不会被推平超过 次。
最终复杂度 。
常数看起来很大,但是实际上跑得很快,不是很懂。
Code
#include<bits/stdc++.h> //#define int long long #define ll long long #define ull unsigned long long #define ld long double #define PII pair<int,int> #define INF 0x3f3f3f3f #define INFLL 0x3f3f3f3f3f3f3f3f #define chkmax(a,b) a=max(a,b) #define chkmin(a,b) a=min(a,b) #define rep(k,l,r) for(int k=l;k<=r;++k) #define per(k,r,l) for(int k=r;k>=l;--k) #define cl(f,x) memset(f,x,sizeof(f)) using namespace std; bool M1; void file_IO() { // freopen("mushroom.in","r",stdin); // freopen("mushroom.out","w",stdout); } const int N=1e5+5; int a[N],n,q; vector<int> vec[N]; vector<PII> g[N]; inline int pre(const vector<int> &vec,const int& x) { auto p=upper_bound(vec.begin(),vec.end(),x); if(p!=vec.begin()) return *(--p); return -1; } inline int nxt(const vector<int> &vec,const int& x) { auto p=lower_bound(vec.begin(),vec.end(),x); if(p!=vec.end()) return *p; return -1; } struct PSGT { struct node { int lson,rson,val; }; node tree[N*20]; int p; inline int new_node(const int& k) { tree[++p]=tree[k]; return p; } inline void push_up(const int& k) { tree[k].val=min(tree[tree[k].lson].val,tree[tree[k].rson].val); } void update(int &k,const int& l,const int& r,const int& qx,const int& val) { k=new_node(k); if(l==r) { tree[k].val=val; return; } int mid=(l+r)>>1; if(qx<=mid) update(tree[k].lson,l,mid,qx,val); if(qx>=mid+1) update(tree[k].rson,mid+1,r,qx,val); push_up(k); } int query(const int& k,const int& l,const int& r,const int& ql,const int& qr) { if(l==r) return l; int mid=(l+r)>>1,val=tree[tree[k].lson].val; if(val<ql) return query(tree[k].lson,l,mid,ql,qr); return query(tree[k].rson,mid+1,r,ql,qr); } int root[N],cnt; inline void ins(const int& x) { ++cnt; root[cnt]=root[cnt-1]; update(root[cnt],0,n,x,cnt); } }; PSGT T2; inline int mex(const int& l,const int& r) { return T2.query(T2.root[r],0,n,l,r); } struct ODT { struct node { int l,r; mutable int val; node() { l=r=val=0; } node(int _l,int _r,int _val) { l=_l; r=_r; val=_val; } bool operator < (const node &tmp) const { return l<tmp.l; } }; set<node> s; ODT() { s.clear(); s.insert(node{1,n,0}); } auto split(int pos) { auto p=s.lower_bound(node(pos,0,0)); if(p!=s.end()&&(*p).l==pos) return p; --p; if((*p).r<pos) return s.end(); int l=(*p).l,r=(*p).r,val=(*p).val; s.erase(p); s.insert(node(l,pos-1,val)); auto t=s.insert(node(pos,r,val)); return t.first; } void assign(int l,int r,int val) { auto _r=split(r+1),_l=split(l); s.erase(_l,_r); s.insert(node(l,r,val)); } auto ins(int p,int val) { auto t=s.insert(node(p,p,val)); return t.first; } }; ODT T,T1; int ans[N]; inline void solve() { scanf("%d",&n); rep(i,1,n) { scanf("%d",&a[i]); vec[a[i]].push_back(i); T2.ins(a[i]); } rep(i,1,n) { if(a[i]) g[0].push_back({i,i}); else g[1].push_back({i,i}); } rep(i,1,n) { for(auto x:g[i-1]) { int l=x.first,r=x.second; int pl=pre(vec[i-1],l),pr=nxt(vec[i-1],r); if(pl!=-1) g[mex(pl,r)].push_back({pl,r}); if(pr!=-1) g[mex(l,pr)].push_back({l,pr}); } sort(g[i].begin(),g[i].end(),[](const PII &a,const PII &b) { return a.first>b.first||(a.first==b.first&&a.second<b.second); }); vector<PII> tmp; int last=INF; for(auto x:g[i]) { if(last>x.second) tmp.push_back(x); chkmin(last,x.second); } swap(g[i],tmp); } T1=ODT(); per(i,n+1,0) { T=ODT(); for(auto x:g[i]) { int l=x.first,r=x.second; int pl=pre(vec[i],l),pr=nxt(vec[i],r); if(pl==-1) pl=1; else ++pl; if(pr==-1) pr=n; else --pr; T.assign(r-l+1,pr-pl+1,1); } for(auto x:T.s) { int l=x.l,r=x.r,val=x.val; if(!val) T1.assign(l,r,i); } } for(auto x:T1.s) { int l=x.l,r=x.r,val=x.val; rep(i,l,r) printf("%d ",val); } } bool M2; signed main() { file_IO(); int testcase=1; //scanf("%d",&testcase); while(testcase--) solve(); // cerr<<"used time = "<<1000.0*clock()/CLOCKS_PER_SEC<<"ms\n"; // cerr<<"used memory = "<<(&M1-&M2)/1024/1024<<"MB\n"; return 0; } -
- 1
信息
- ID
- 9587
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者