COGS2485 从零开始的序列

传送门

题意:给定一个长为$n$的序列,定义$f(x)$表示所有(长为$x$的区间最小值)的最大值,求$f(1)$~$f(n)$。

看好多人都用并查集做的,然而我并不想写……既然品酒大会可以后缀数组+并查集也可以直接用后缀树递推,那这个问题直接上树再递推也行吧……

跟RMQ有关的一个树形结构就是笛卡尔树,那么我们构建笛卡尔树后自底向上递推一遍即可,对每个节点更新它对应区间长度的答案,最后根据$f(x)ge f(x+1)$更新一遍所有的$f$即可。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int maxn=200010;
 6 void bfs();
 7 int n,a[maxn],f[maxn],root,lc[maxn]={0},rc[maxn]={0},s[maxn],top=0,q[maxn],size[maxn]={0};
 8 int main(){
 9     freopen("sky_seq.in","r",stdin);
10     freopen("sky_seq.out","w",stdout);
11     memset(f,-63,sizeof(f));
12     scanf("%d",&n);
13     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
14     s[++top]=root=1;
15     for(int i=2;i<=n;i++){
16         s[top+1]=0;
17         while(a[i]<a[s[top]])top--;
18         if(top)rc[s[top]]=i;
19         else root=i;
20         lc[i]=s[top+1];
21         s[++top]=i;
22     }
23     bfs();
24     for(int i=n;i;i--)f[i]=max(f[i],f[i+1]);
25     for(int i=1;i<=n;i++)printf("%d ",f[i]);
26     return 0;
27 }
28 void bfs(){
29     int x,head=1,tail=1;
30     q[tail++]=root;
31     while(head!=tail){
32         x=q[head++];
33         size[x]=1;
34         if(lc[x])q[tail++]=lc[x];
35         if(rc[x])q[tail++]=rc[x];
36     }
37     for(int i=n;i;i--){
38         x=q[i];
39         size[x]+=size[lc[x]]+size[rc[x]];
40         f[size[x]]=max(f[size[x]],a[x]);
41     }
42 }
View Code

lyc说这个题是从CF上搬过来的,然而他也忘了是哪道题了……麻烦知道的dalao在评论里告诉我一声……

原文地址:https://www.cnblogs.com/hzoier/p/6488703.html