Codeforces Round 1019 (Div. 2)_D. Local Construction

//首先思路是,对于每一轮,假如是奇数轮次,我们只需要让当前轮次的所有数尽可能大即可,反之则尽可能小。所以用l=1和r=n来放答案
//对于当前轮次,如果是奇数,很明显只需要挨个从r往小放即可,因为这样已经保证了后面放的所有数都比当前放的小,也就是当前放的数不会是局部最小值
//现在还剩下一个问题,那就是边界情况。例如1 1 1 -1 1 1 1,如果我们直接从前往后放的话,会变成7 6 5 1 4 3 2,此时2变成了局部最小值。
//所以只需要对于当前轮次的后缀我们反着放就行了把它变成7 6 5 1 2 3 4就行
#include<bits/stdc++.h>
    
using namespace std;
    
int t;
const int N = 2e5 + 10;
int n,a[N];
    
void solve() {
    cin >> n;
    int tmp = 0;
    for(int i = 1;i <= n;i++) cin >> a[i],tmp = max(tmp,a[i]);
    vector<int> ans(n + 10);
    int r = n,l = 1;
    for(int i = 1;i <= tmp;i++) {
        int pos = n + 1;
        for(int j = n;j >= 1;j--) {
            if(a[j] == -1 || a[j] > i) break;
            else if(a[j] == i && pos == n + 1) pos = j;
        }
        if(pos <= n)
        for(;pos >= 1;pos--)
            if(a[pos] == -1 || a[pos] > i) break;
            else if(a[pos] == i) {
                if(i & 1) ans[pos] = r--;
                else ans[pos] = l++;
            }
        for(int k = 1;k <= n;k++) {
            if(a[k] == i && !ans[k]) {
                if(i & 1) ans[k] = r--;
                else ans[k] = l++;
            }
        }
    }
    for(int i = 1;i <= n;i++) if(a[i] == -1) ans[i] = l;
    for(int i = 1;i <= n;i++) cout << ans[i] << ' ';
    cout << '\n';
}
    
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin >> t;
    while(t--) solve();
    
    return 0;
}
posted @ 2025-04-23 14:10  孤枕  阅读(16)  评论(0)    收藏  举报