专栏文章

题解:CF2031D Penchick and Desert Rabbit

CF2031D题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mir45ypv
此快照首次捕获于
2025/12/04 15:27
3 个月前
此快照最后确认于
2025/12/04 15:27
3 个月前
查看原文

D

赛时的清奇想法。
首先发现能跳跃的两个位置是逆序对,因此考虑用并查集维护,并记录集合内最大值与最小值。
再考虑这样一种做法,先遍历一遍数组,目前遇到的最大值为 xx,下标为 idid,加入一个数 aia_i
  • ai>=xa_i>=x 更新 xxidid
  • ai<xa_i<x 那么就合并 iiidid
以最后一组样例为例:
mximx_i 表示集合 ii 中最大的 aia_imiimi_i 表示最小值。
然后考虑合并不同集合,从后往前,如果出现两个不同集合 i,ji,ji<ji<j。由前面的过程易知 mximxjmx_i \le mx_j,如果 mxi>mijmx_i>mi_j,就说明这两个集合可以合并。
那有没有可能出现不是相邻的集合合并呢?答案是否定的,考虑 k,i,jk,i,j 三个集合,mxkmximxjmx_k \le mx_i \le mx_j,如果 iijj 不能合并,则 mximijmx_i \le mi_j,就会有 mxkmximijmx_k \le mx_i \le mi_j,显然 kkjj 不能合并。因此每个集合都只能和相邻的集合合并。
CPP
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>

using namespace std;
typedef long long ll;
const int N=5e5+5;
int n;
int a[N],ans[N];
int fa[N],mi[N],mx[N];
int find(int x)
{
    if(x==fa[x]) return x;
    return fa[x]=find(fa[x]);
}
void merge(int x,int y)
{
    x=fa[x],y=fa[y];
    fa[y]=x;
    mi[x]=min(mi[x],mi[y]);
    mx[x]=max(mx[x],mx[y]);
}
void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++) 
    {
        cin>>a[i];
        fa[i]=i;
        mi[i]=mx[i]=a[i];
    }
    int x=a[1],id=1;
    for(int i=2;i<=n;i++) 
    {
        if(a[i]<x) merge(id,i);
        else x=a[i],id=i;
    }
    
    for(int i=n-1;i>=1;i--)
        if(find(i)!=find(i+1)&&mi[find(i+1)]<mx[find(i)])
            merge(i,i+1);
    for(int i=1;i<=n;i++) cout<<mx[find(i)]<<' ';
    cout<<'\n';
}
int main ()
{
    #ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    #endif 
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int T;
    cin>>T;
    while(T--) solve();
    return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...