【AtCoder Grand Contest 001F】Wide Swap [线段树][拓扑]

Wide Swap

Time Limit: 50 Sec  Memory Limit: 512 MB

Description

  

Input

  

Output

  

Sample Input

  8 3
  4 5 7 8 3 1 2 6

Sample Output

  1
  2
  6
  7
  5
  3
  4
  8

HINT

  

Solution

  首先,直接做难度系数较高,假设原序列为a,我们考虑设一个pp[a_i] = i,即将题目中的权值与下标调换

  那么显然,要令a字典序最小,只要让p字典序最小即可。因为“权值小的尽量前”“前面的权值尽量小”是一个意思。

  现在操作转化为:相邻元素权值差>=k的可以换顺序。

  考虑一个暴力怎么做,显然是 i后面的所有 j 比,如果 abs(p_i - p_j) < k,则 i 和 j 的相对顺序就确定了, 连一条 p_i -> p_j 的边。

  连边之后跑一边拓扑即可。

  显然复杂度在于连边,因为这样暴力会有很多无用边。比如A->B, B->C, A->C,这条A->C显然无用

  我们考虑如何删掉 A->C 这种边。

  倒着加入,显然 p_i 连向 (p_i-k, p_i)∪(p_i, p_i+k)。我们只需要分别连向两个区间中下标最小的那一个即可。用线段树维护一下区间最小值

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 #define next nxt
 13 const int ONE = 1000005;
 14 const int INF = 2147483640;
 15 
 16 int get()
 17 {
 18         int res = 1, Q = 1; char c;
 19         while( (c = getchar()) < 48 || c > 57)
 20             if(c == '-') Q = -1;
 21         if(Q) res = c - 48;
 22         while( (c = getchar()) >= 48 && c <= 57)
 23             res = res * 10 + c - 48;
 24         return res * Q;
 25 }
 26 
 27 int n, k;
 28 int A[ONE], p[ONE];
 29 int next[ONE], first[ONE], go[ONE], Input[ONE], tot;
 30 priority_queue <int, vector <int>, greater <int> > q;
 31 
 32 int res = INF;
 33 namespace Seg
 34 {
 35         struct power {int val;} Node[ONE * 4];
 36         void Build(int i, int l, int r)
 37         {
 38             Node[i].val = INF;
 39             if(l == r) return;
 40             int mid = l + r >> 1;
 41             Build(i << 1, l, mid), Build(i << 1 | 1, mid + 1, r);
 42         }
 43 
 44         void Update(int i, int l, int r, int L, int x)
 45         {
 46             if(L <= l && r <= L)
 47             {
 48                 Node[i].val = x;
 49                 return;
 50             }
 51             int mid = l + r >> 1;
 52             if(L <= mid) Update(i << 1, l, mid, L, x);
 53             else Update(i << 1 | 1, mid + 1, r, L, x);
 54             Node[i].val = min(Node[i << 1].val, Node[i << 1 | 1].val);
 55         }
 56 
 57         void Query(int i, int l, int r, int L, int R)
 58         {
 59             if(L > R) return;
 60             if(L <= l && r <= R)
 61             {
 62                 res = min(res, Node[i].val);
 63                 return;
 64             }
 65             int mid = l + r >> 1;
 66             if(L <= mid) Query(i << 1, l, mid, L, R);
 67             if(mid + 1 <= R) Query(i << 1 | 1, mid + 1, r, L, R);
 68         }
 69 }
 70 
 71 void Add(int u, int v)
 72 {
 73         Input[v]++, next[++tot] = first[u], first[u] = tot, go[tot] = v;
 74 }
 75 
 76 void Deal()
 77 {
 78         int now = 0;
 79         for(int i = 1; i <= n; i++)
 80             if(!Input[i]) q.push(i);
 81         while(!q.empty())
 82         {
 83             int u = q.top(); q.pop();
 84             A[u] = ++now;
 85             for(int e = first[u]; e; e = next[e])
 86             {
 87                 int v = go[e];
 88                 if(--Input[v] == 0) q.push(v);
 89             }
 90         }
 91         for(int i = 1; i <= n; i++) printf("%d\n", A[i]);
 92 }
 93 
 94 int main()
 95 {
 96         n = get(), k = get();
 97         for(int i = 1; i <= n; i++) p[get()] = i;
 98 
 99         Seg::Build(1, 1, n);
100         for(int i = n; i >= 1; i--)
101         {
102             res = INF, Seg::Query(1, 1, n, p[i] + 1, min(p[i] + k - 1, n));
103             if(res != INF) Add(p[i], p[res]);
104 
105             res = INF, Seg::Query(1, 1, n, max(1, p[i] - k + 1), p[i] - 1);
106             if(res != INF) Add(p[i], p[res]);
107 
108             Seg::Update(1, 1, n, p[i], i);
109         }
110 
111         Deal();
112 }
View Code

 

posted @ 2017-11-25 16:49  BearChild  阅读(...)  评论(...编辑  收藏