1364 最大字典序排列

萌萌哒的传送门


System Messag 大神的题解。这个题目明显是要贪心的。从前往后每次看看能不能拿一个大的放到当前数字的前面,而且要拿尽可能大的。这样字典序才会变成最大。

原数组设为a[i]

这个过程可以用线段树来维护。先按照原数组建立线段树。树结点中记录最大值,最大值所在位置,当前区间有几个数字没有被删除。

然后从前往后开始,设当前位置为P,剩K步可以拿,那么就要从P后面拿一个a[Q],他要比a[P]大且区间[P,Q]未删除数字个数不超过K+1。可以先找到距离P最远X的且[P,X]里面未删除的数字不超过K+1个。然后查询[P,X]中最大值,如果比a[P]大就可以换了,不然的话就P++Q放到前面之后就在线段树里面进行删除。

距离P最远X的且[P,X]里面未删除的数字不超过K+1个,这一步可以通过找[0,X]不超过某个数字来做,可以有logn.

 

以上步骤均可以在logn以内实现,所以总复杂度是nlogn


弱写的代码:

#include <iostream>
#include <stdio.h>
#include <map>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long ll;

template<class T>
void read(T & x) {
    char ch = getchar();
    bool sign = false;
    x = 0;
    while (ch < '0' || ch > '9') {
        if (ch == '-') sign = true;
        ch = getchar();
    }
    while ('0' <= ch && ch <= '9') {
        x = 10 * x + ch - '0';
        ch = getchar();
    }
    if (sign) x = -x;
}

template<class T>
void print(T x) {
    if (x > 9) print(x / 10);
    putchar('0' + (x % 10));
}

template<class T>
void println(T x) {
    print(x);
    puts("");
}

template<class T>
inline T sqr(T a) {
    return a * a;
}

//=============================================
const int N = 1e5 + 5;
#define ls u << 1
#define rs u << 1 | 1
#define mid ((l + r) >> 1)
#define lson u << 1,l,mid
#define rson u << 1 | 1,mid + 1,r
typedef pair<int,int> PAIR;
struct Tree {
    int Max[N << 2],num[N << 2],id[N << 2];
    void pushup(int u) {
        num[u] = num[ls] + num[rs];
        int tp = (Max[ls] < Max[rs] ? rs : ls);
        Max[u] = Max[tp];
        id[u] = id[tp];
    }
    void build(int u,int l,int r) {
        if(l == r) {
            scanf("%d",Max + u);
            num[u] = 1;
            id[u] = l;
        } else {
            build(lson);
            build(rson);
            pushup(u);
        }
    }
    void Delete(int u,int l,int r,int x) {
        if(l == r) {
            Max[u] = num[u] = id[u] = 0;
        } else {
            if(x <= mid) Delete(lson,x);
            else Delete(rson,x);
            pushup(u);
        }
    }
    PAIR QueMaxId(int u,int l,int r,int x,int y) {
        if(x <= l && y >= r) {
            return make_pair(Max[u],id[u]);
        } else {
            PAIR tp,ans = make_pair(0,0);
            if(x <= mid) {
                tp = QueMaxId(lson,x,y);
                if(tp.first > ans.first) ans = tp;
            }
            if(y > mid) {
                tp = QueMaxId(rson,x,y);
                if(tp.first > ans.first) ans = tp;
            }
            return ans;
        }
    }
    int que_num(int u,int l,int r,int x,int y) {
        if(x <= l && y >= r) {
            return num[u];
        } else {
            int tp = 0;
            if(x <= mid) tp += que_num(lson,x,y);
            if(y > mid) tp += que_num(rson,x,y);
            return tp;
        }
    }
    int que(int u,int l,int r,int x,int k) {
        if(l == r) {
            return l;
        } else {
            if(k <= num[ls]) return que(lson,x,k);
            else return que(rson,x,k - num[ls]);
        }
    }
}ac;

int main() {
    int n,k,num = 0;
    read(n);
    read(k);
    ac.build(1,1,n);
    for(int i = 1; num < n; i++) {
        int id = ac.que(1,1,n,n,k + 1);
        PAIR tmp = ac.QueMaxId(1,1,n,i,id);
        printf("%d\n",tmp.first);
        ac.Delete(1,1,n,tmp.second);
        k -= ac.que_num(1,1,n,1,tmp.second);
        if(tmp.second != i) i--;
        num++;
    }
}



你可能感兴趣的:(线段树,贪心)