HDU 5338 ZZX and Permutations 线段树

题目链接:HDU 5338
题意:给一个去掉括号的置换半成品,问如何加括号可以使原序列字典序最大。
思路:
思路很明确

  • 1、肯定是贪心的考虑使靠前位置的尽量大。
  • 2、那么就找从当前位置到之前的右括号之间最大的值与后继进行比较。
  • 括号直接用SET维护就可以了,最大值用线段树维护。比赛的时候SB用线段树维护的右括号位置,幸亏范围小。

代码:

#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
#include <algorithm>
#define Lson o<<1,l,mid
#define Rson o<<1|1,mid+1,r
#define MID int mid = (l+r)>>1

using namespace std;

const int maxn=100100;
int data[maxn],fd[maxn];
//namespace SGM1{
//    set<int> st;
//    int init(int n){
//        st.clear();
//        st.insert(0);
//    }
//    int get(int pos){
//        return 0-*st.lower_bound(-pos);
//    }
//    int update(int pos){
//        st.insert(-pos);
//    }
//}

namespace SGM1{
    int maxv[maxn*4];
    int maxe=-1,n;
    void init(int _n){
        n=_n;
        for(int i=0;i<4*maxn;i++){
            maxv[i]=0;
        }
    }
    void modify(int o,int l,int r,int pos){
        if(l==r){
            maxv[o]=pos;
            return ;
        }
        MID;
        if(pos<=mid)modify(Lson,pos);
        else  modify(Rson,pos);
        maxv[o]=max(maxv[o<<1],maxv[o<<1|1]);
    }
    void quarry(int o,int l,int r,int L,int R){
        if(L<=l&&r<=R){
            maxe=max(maxe,maxv[o]);
            return ;
        }
        MID;
        if(L<=mid)quarry(Lson,L,R);
        if(R>mid )quarry(Rson,L,R);
    }
    int get(int pos){
        maxe=-1;
        quarry(1,1,n,1,pos);
        return maxe;
    }
    int update(int pos){
        modify(1,1,n,pos);
    }
}
namespace SGM2{
    int maxv[maxn*4];
    int maxe,n;
    int a[maxn];
    int maxa(int x,int y){
        if(a[x]>a[y]) return x;
        return y;
    }
    void build(int o,int l,int r){
        if(l==r){
            maxv[o]=l;
            return ;
        }
        MID;
        build(Lson);
        build(Rson);
        maxv[o]=maxa(maxv[o<<1],maxv[o<<1|1]);
    }
    void init(int _n){
        n=_n;
        a[0]=0;
        for(int i=1;i<=n;i++)a[i]=data[i];
        build(1,1,n);
    }

    void modify(int o,int l,int r,int pos){
        if(l==r){
            maxv[o]=l;
            return ;
        }
        MID;
        if(pos<=mid)modify(Lson,pos);
        else  modify(Rson,pos);
        maxv[o]=maxa(maxv[o<<1],maxv[o<<1|1]);
    }
    void quarry(int o,int l,int r,int L,int R){
        if(L<=l&&r<=R){
            maxe=maxa(maxe,maxv[o]);
            return ;
        }
        MID;
        if(L<=mid)quarry(Lson,L,R);
        if(R>mid )quarry(Rson,L,R);
    }
    int get(int L,int R){
        maxe=0;
        quarry(1,1,n,L,R);
        return maxe;
    }
    void update(int pos){
        a[pos]=0;
        modify(1,1,n,pos);
    }
}
int ans[maxn];
int main(){
    int n,T;
   // freopen("data.txt","r",stdin);
    scanf("%d",&T);
    while(T--){
        memset(ans,0,sizeof(ans));
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&data[i]);
            fd[data[i]]=i;

        }
        SGM1::init(n);
        SGM2::init(n);
        for(int i=1;i<=n;i++){
            if(!ans[i]){
                int tpos=SGM1::get(fd[i])+1;
                tpos=SGM2::get(tpos,fd[i]);
                if(data[tpos]>data[fd[i]+1]||SGM1::get(fd[i]+1)>=fd[i]+1||fd[i]==n){
                    SGM1::update(tpos);
                    SGM1::update(fd[i]);
                    for(int j=tpos;j<fd[i];j++){
                        ans[data[j]]=data[j+1];
                    }
                    ans[i]=data[tpos];
                }
                else{
                    SGM2::update(fd[i]+1);
                    ans[i]=data[fd[i]+1];
                }
            }
        }
        for(int i=1;i<=n;i++){
            if(i>1)putchar(' ');
            printf("%d",ans[i]);
        }
        puts("");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值