【AtCoder Regular Contest 080E】Young Maids [堆][线段树]
Young Maids
Time Limit: 50 Sec Memory Limit: 512 MBDescription
给定一个排列,每次选出相邻的两个放在队头,要求字典序最小。
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 }