【AtCoder Regular Contest 080E】Young Maids [堆][线段树]

Young Maids

Time Limit: 50 Sec  Memory Limit: 512 MB

Description

  给定一个排列,每次选出相邻的两个放在队头,要求字典序最小。

Input

  第一行一个整数n,第二行n个数表示这个排列。

Output

  n个数表示答案。

Sample Input

  8
  4 6 3 2 8 5 7 1

Sample Output

  3 1 2 7 4 6 8 5

HINT

  n%2=0,2 <= n <= 2e5

Solution

  倒着考虑。
  我们维护一个小根,堆里面存[l, r, val],表示在区间[l, r]中选择两个元素,第一个元素A的权值为val(保证合法),以val为第一关键字

  那么显然,我们每次选出堆顶进行操作

  显然,若我们取走了A,B(pos[A] < pos[B])[l,r]就被拆成了 [l,A-1], [A+1,B-1], [B+1,r],我们要保证每一个区间长度都是偶数
  那么只要有,pos[A]%2 == pos[l]%2,pos[B]%2 == pos[r]%2
  又由于我们每次减少两个数,所以这样显然可以保证 pos[B]-pos[A]+1 % 2 == 0


  现在问题就是怎么求出A、B具体是那两个数,显然写个线段树维护一下 某段区间内奇数/偶数位置的min_val和所在的pos即可。

Code

  1 #include<iostream>
  2 #include<string>
  3 #include<algorithm>
  4 #include<cstdio>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cmath>
  8 #include<queue>
  9 using namespace std;
 10 typedef long long s64;
 11 
 12 const int ONE = 200005;
 13 const int INF = 2147483640;
 14 
 15 int get()
 16 {
 17         int res = 1, Q = 1; char c;
 18         while( (c = getchar()) < 48 || c > 57)
 19             if(c == '-') Q = -1;
 20         if(Q) res = c - 48;
 21         while( (c = getchar()) >= 48 && c <= 57)
 22             res = res * 10 + c - 48;
 23         return res * Q;
 24 }
 25 
 26 int n;
 27 int a[ONE];
 28 
 29 struct point
 30 {
 31         int id, val;
 32         friend bool operator <(point a, point b)
 33         {
 34             if(a.val != b.val) return a.val < b.val;
 35             return a.id < b.id;
 36         }
 37 };
 38 point res;
 39 
 40 namespace Seg
 41 {
 42         struct power {point odd, eve;} Node[ONE * 4];
 43         
 44         void Build(int i, int l, int r)
 45         {
 46             Node[i].odd.val = Node[i].eve.val = INF;
 47             if(l == r)
 48             {
 49                 if(l & 1) Node[i].odd = (point){l, a[l]};
 50                 else Node[i].eve = (point){l, a[l]};
 51                 return;
 52             }
 53             int mid = l + r >> 1;
 54             Build(i << 1, l, mid), Build(i << 1 | 1, mid + 1, r);
 55             Node[i].odd = min(Node[i << 1].odd, Node[i << 1 | 1].odd);
 56             Node[i].eve = min(Node[i << 1].eve, Node[i << 1 | 1].eve);
 57         }
 58 
 59         void Query(int i, int l, int r, int L, int R, int opt)
 60         {
 61             if(L <= l && r <= R)
 62             {
 63                 if(opt == 1) res = min(res, Node[i].odd);
 64                 else res = min (res, Node[i].eve);
 65                 return;
 66             }
 67             int mid = l + r >> 1;
 68             if(L <= mid) Query(i << 1, l, mid, L, R, opt);
 69             if(mid + 1 <= R) Query(i << 1 | 1, mid + 1, r, L, R, opt);
 70         }
 71 }
 72 
 73 struct power
 74 {
 75         int l, r, val;
 76         bool operator <(power a) const
 77         {
 78             if(a.val != val) return a.val < val;
 79             return a.l < l;
 80         }
 81 };
 82 priority_queue <power> q;
 83 
 84 point Get(int l, int r, int opt)
 85 {
 86         res = (point){n + 1, INF};
 87         Seg::Query(1, 1, n, l, r, opt);
 88         return res;
 89 }
 90 
 91 void Add(int l, int r)
 92 {
 93         if(l > r) return;
 94         q.push((power){l, r, Get(l, r, l % 2).val});
 95 }
 96 
 97 int main()
 98 {
 99         n = get();
100         for(int i = 1; i <= n; i++)
101             a[i] = get();
102 
103         Seg::Build(1, 1, n);
104         Add(1, n);
105 
106         for(int i = 1; i <= n / 2; i++)
107         {
108             power u = q.top(); q.pop();
109             point A = Get(u.l, u.r - 1, u.l % 2);
110             point B = Get(A.id + 1, u.r, u.r % 2);
111             printf("%d %d ", A.val, B.val);
112 
113             Add(u.l, A.id - 1), Add(A.id + 1, B.id - 1), Add(B.id + 1, u.r);
114         }
115 }
View Code

 

posted @ 2017-12-01 21:49  BearChild  阅读(321)  评论(0编辑  收藏  举报