【AtCoder Regular Contest 080E】Young Maids [堆][线段树]
2017-12-01 21:49
656 查看
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
#include<iostream> #include<string> #include<algorithm> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<queue> using namespace std; typedef long long s64; const int ONE = 200005; const int INF = 2147483640; int get() { int res = 1, Q = 1; char c; while( (c = getchar()) < 48 || c > 57) if(c == '-') Q = -1; if(Q) res = c - 48; while( (c = getchar()) >= 48 && c <= 57) res = res * 10 + c - 48; return res * Q; } int n; int a[ONE]; struct point { int id, val; friend bool operator <(point a, point b) { if(a.val != b.val) return a.val < b.val; return a.id < b.id; } }; point res; namespace Seg { struct power {point odd, eve;} Node[ONE * 4]; void Build(int i, int l, int r) { Node[i].odd.val = Node[i].eve.val = INF; if(l == r) { if(l & 1) Node[i].odd = (point){l, a[l]}; else Node[i].eve = (point){l, a[l]}; return; } int mid = l + r >> 1; Build(i << 1, l, mid), Build(i << 1 | 1, mid + 1, r); Node[i].odd = min(Node[i << 1].odd, Node[i << 1 | 1].odd); Node[i].eve = min(Node[i << 1].eve, Node[i << 1 | 1].eve); } void Query(int i, int l, int r, int L, int R, int opt) { if(L <= l && r <= R) { if(opt == 1) res = min(res, Node[i].odd); else res = min (res, Node[i].eve); return; } int mid = l + r >> 1; if(L <= mid) Query(i << 1, l, mid, L, R, opt); if(mid + 1 <= R) Query(i << 1 | 1, mid + 1, r, L, R, opt); } } struct power { int l, r, val; bool operator <(power a) const { if(a.val != val) return a.val < val; return a.l < l; } }; priority_queue <power> q; point Get(int l, int r, int opt) { res = (point){n + 1, INF}; Seg::Query(1, 1, n, l, r, opt); return res; } void Add(int l, int r) { if(l > r) return; q.push((power){l, r, Get(l, r, l % 2).val}); } int main() { n = get(); for(int i = 1; i <= n; i++) a[i] = get(); Seg::Build(1, 1, n); Add(1, n); for(int i = 1; i <= n / 2; i++) { power u = q.top(); q.pop(); point A = Get(u.l, u.r - 1, u.l % 2); point B = Get(A.id + 1, u.r, u.r % 2); printf("%d %d ", A.val, B.val); Add(u.l, A.id - 1), Add(A.id + 1, B.id - 1), Add(B.id + 1, u.r); } }View Code
相关文章推荐
- 【递归】【线段树】【堆】AtCoder Regular Contest 080 E - Young Maids
- (线段树/贪心)AtCoder Regular Contest 080 E : Old Maid
- AtCoder Regular Contest 080 E - Young Maids 贪心+堆+RMQ
- AtCoder Regular Contest 080 E - Young Maids [拓扑序+分治+奇偶rmq]||[分块]
- AtCoder Regular Contest 080 E - Young Maids
- AtCoder Regular Contest 069 F - Flags 2-SAT+线段树优化建图
- AtCoder Regular Contest 080 E - Young Maids(线段树+优先队列)
- AtCoder Regular Contest 073 F - Many Moves 线段树优化dp
- AtCoder Regular Contest 076 F - Exhausted? 霍尔定理+线段树
- AtCoder Regular Contest 085 F NRE 线段树优化dp
- AtCoder Regular Contest 076E Coneected?
- AtCoder Regular Contest 058 D - Iroha and a Grid 组合数学
- (dp)AtCoder Regular Contest 081 E - Don't Be a Subsequence
- AtCoder Regular Contest 065 Shuffling 动态规划
- Atcoder Regular Contest 081 总结
- AtCoder Regular Contest 092 C - 2D Plane 2N Points 贪心 匈牙利算法模板
- 【推导】【模拟】AtCoder Regular Contest 082 F - Sandglass
- AtCoder Regular Contest 079 C D E
- 【AtCoder Regular Contest 082 F】Sandglass
- 【2-SAT】【优化连边】【AtCoder Regular Contest 069 F】Flag