题意:给定一个长为$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 }
lyc说这个题是从CF上搬过来的,然而他也忘了是哪道题了……麻烦知道的dalao在评论里告诉我一声……