COGS 2485. [HZOI 2016]从零开始的序列
2485. [HZOI 2016]从零开始的序列
★★ 输入文件:sky_seq.in
输出文件:sky_seq.out
简单对比
时间限制:1 s 内存限制:256 MB
【题目描述】
这个名字只是吸引你们这些死宅过来的。跟题目没关系。
现在Sky_miner给你一个序列,定义f(x)为(所有长度为x的区间中的最小值)的最大值.
要求输出f(1) .. f(n)
1 <= n <= 2*10^5
【输入格式】
第一行一个正整数n,含义如题
第二行共n个整数,为给定的序列,每一个整数 -10000 <= x <= 10000
【输出格式】
一行,共n个正整数,分别为f(1) f(2) .. f(n)
【样例输入】
5
3 4 1 3 9
【样例输出】
9 3 1 1 1
【来源】
HZOI 2016
分析:
大概有两种做法...
一种是比较直接的并查集做法...
就是我们把元素从大到小排序,依次加入序列中,然后并查集维护联通块的大小,更新答案,最后因为$f[i]>=f[i+1]$再$O(N)$更新一遍就好了...
一种是单调栈做法...
维护$l[i]r[i]$代表以$a[i]$为最小值所能扩展到最远的子序列,然后更新答案...
代码:
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> //by NeighThorn using namespace std; const int maxn=200000+5; int n,a[maxn],f[maxn],fa[maxn],siz[maxn],pos[maxn],vis[maxn]; inline int read(void){ char ch=getchar();int f=1,x=0; while(!(ch>='0'&&ch<='9')){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return f*x; } inline int find(int x){ return fa[x]==x?x:fa[x]=find(fa[x]); } inline bool cmp(int x,int y){ return a[x]>a[y]; } signed main(void){ freopen("sky_seq.in","r",stdin); freopen("sky_seq.out","w",stdout); n=read();memset(f,-1,sizeof(f)); for(int i=1;i<=n;i++) a[i]=read(),fa[i]=i,siz[i]=1,pos[i]=i; sort(pos+1,pos+n+1,cmp); for(int i=1;i<=n;i++){ vis[pos[i]]=1; if(pos[i]>1&&vis[pos[i]-1]){ int fx=find(pos[i]-1); siz[pos[i]]+=siz[fx],fa[fx]=pos[i]; } if(pos[i]<n&&vis[pos[i]+1]){ int fx=find(pos[i]+1); siz[pos[i]]+=siz[fx],fa[fx]=pos[i]; } if(f[siz[pos[i]]]==-1) f[siz[pos[i]]]=a[pos[i]]; } for(int i=n-1;i>=1;i--) f[i]=max(f[i],f[i+1]); for(int i=1;i<=n;i++) printf("%d ",f[i]);puts(""); fclose(stdin);fclose(stdout); return 0; }
By NeighThorn