51nod-1364 最大字典序排列(线段树)

来源:互联网 发布:单片机种类 编辑:程序博客网 时间:2024/05/22 09:48

原题链接

1364 最大字典序排列
基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题
 收藏
 关注
给出一个1至N的排列,允许你做不超过K次操作,每次操作可以将相邻的两个数交换,问能够得到的字典序最大的排列是什么?
例如:N = 5, {1 2 3 4 5},k = 6,在6次交换后,能够得到的字典序最大的排列为{5 3 1 2 4}。
Input
第1行:2个数N, K中间用空格分隔(1 <= N <= 100000, 0 <= K <= 10^9)。第2至N + 1行:每行一个数i(1 <= i <= N)。
Output
输出共N行,每行1个数,对应字典序最大的排列的元素。
Input示例
5 612345
Output示例
53124
维护两个线段树num[], cnt[], 在num中[l, r]表示该区间元素的最大值,cnt[]中[l, r]表示区间里有多少个元素

每次根据k, n算出最远的一个元素j(通过相邻位置的交换能到最前面), 根据cnt线段树查询第j个元素的值,求出下标r, 在根据num线段树求出[1, r]中的最大值,直接输出最大值,把最大值的位置在num[]和cnt[]中赋值为0,相当于没有这个位置,循环操作

#include <bits/stdc++.h>#define maxn 100005#define MOD 1000000007using namespace std;typedef long long ll;int num[maxn<<2], cnt, kk[maxn<<2], p[maxn], vis[maxn];void Build(int j, int l, int r){//建树 if(l == r){scanf("%d", num+j);vis[num[j]] = ++cnt;kk[j] = 1;p[cnt] = num[j];return ;}int mid = (l + r) >> 1;Build(j<<1, l, mid);Build(j<<1|1, mid+1, r);num[j] = max(num[j<<1], num[j<<1|1]);kk[j] = kk[j<<1] + kk[j<<1|1];}int Query(int j, int L, int R, int l, int r){//查询区间[l, r]上的最大值 if(L == l && R == r){return num[j];}int mid = (L + R) >> 1;if(r <= mid) return Query(j<<1, L, mid, l, r);if(l > mid) return Query(j<<1|1, mid+1, R, l, r);return max(Query(j<<1, L, mid, l, mid), Query(j<<1|1, mid+1, R, mid+1, r));}void Update(int j, int L, int R, int e){//下标e所在的元素已经放在前面,则该位置没有元素 if(L == R){num[j] = 0;kk[j] = 0;return ;}int mid = (L + R) >> 1;if(mid >= e) Update(j<<1, L, mid, e);else Update(j<<1|1, mid+1, R, e);num[j] = max(num[j<<1], num[j<<1|1]);kk[j] = kk[j<<1] + kk[j<<1|1];}int Query2(int j, int L, int R, int c){//找到第c个元素的值 if(L == R){return num[j];}int mid = (L + R) >> 1;if(kk[j<<1] >= c) return Query2(j<<1, L, mid, c);return Query2(j<<1|1, mid+1, R, c-kk[j<<1]);}int Query3(int j, int L, int R, int l, int r){//查询[l, r]区间里有多少个元素 if(L == l && R == r){return kk[j];}int mid = (L + R) >> 1;if(r <= mid) return Query3(j<<1, L, mid, l, r);if(l > mid) return Query3(j<<1|1, mid+1, R, l, r);return Query3(j<<1, L, mid, l, mid) + Query3(j<<1|1, mid+1, R, mid+1, r);}int main(){//freopen("in.txt", "r", stdin);int n, k;scanf("%d%d", &n, &k);Build(1, 1, n);int l = 1, t = n;while(k && t){int e = min(k+1, t);int h = Query2(1, 1, n, e);     h = vis[h];    h = Query(1, 1, n, 1, h);    printf("%d\n", h);    h = vis[h];    p[h] = 0;    int m = Query3(1, 1, n, 1, h);    k -= m - 1;    t--;    Update(1, 1, n, h);}for(int i = 1; i <= n; i++) if(p[i]) printf("%d\n", p[i]);return 0;}



0 0
原创粉丝点击