BZOJ 2080: [Poi2010]Railway 双栈排序

2080: [Poi2010]Railway

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 140  Solved: 35
[Submit][Status][Discuss]

Description

一个铁路包含两个侧线1和2,右边由A进入,左边由B出去(看下面的图片)
  
有n个车厢在通道A上,编号为1到n,它们被安排按照要求的顺序(a1,a2,a3,a4....an)进入侧线,进去还要出来,它们要按照编号顺序(1,2,3,4,5。。。。n)从通道B出去。他们从A到1或2,然后经过一系列转移从B出去,不用考虑容量问题。

Input

输入:第一行一个整数n(1<=n<=100000)表示要转移的车厢总数,第二行为进入侧线的要求顺序a1.a2.a3.a4....an,由空格隔开。

Output

输出:如果可以按照编号顺序到通道B,则输出两行,第一行为TAK,第二行为n个由空格隔开的整数,表示每个车厢进入的侧线编号(1,2)。否则输出NIE。

Sample Input

[样例输入1]
4
1 3 4 2
[样例输入2]
4
2 3 4 1

Sample Output

[样例输出1]
TAK
1 1 2 1 (1号线进到侧线1,然后出来,3号进入侧线1,4号进入侧线2,2号进入侧线1,然后出来,接着3号出来,4号出来)
[样例输出2]
NIE (不可能。。No)

HINT

 

Source

[Submit][Status][Discuss]

 

分析

本题和 NOIP 2008 提高组 的 双栈排序 是类似的。

 

首先,考虑一个序列满足双栈排序,需要什么样的性质。

发现,如果点i入栈,那么在i之前的值大于a[i]的点都不可能出栈,那么它们出来的时候一定和入栈的顺序刚好相反。

如果,其入栈不是递减的,出栈就不会是递增的。后来发现,这也是序列满足双栈排序的充要条件。

 

因此,对于所有的i<j<k且有a[k]<a[i]<a[k],在i和j之间连边。每条边上的两个点不能在同一个栈中。做染色即可。

 

双栈排序数据太水,不用刻意调整顺序即可AC,而且边很少。

 

然而BZOJ上POI的双栈排序要难多了,数据范围更大,而且还卡格式了。

 

Railway要求只能O(NlogN),考虑机智地遍历图地方式。

对于一个点,如果lim表示最大的下标满足min(lim...n)<num[i],那么i向[i + 1, lim]中所有值大于num[i]的地方都有边,可以用一个按下标维护的线段树来查询区间内最大的num值,即可知道是否有边。

对于一个点,如果low表示min(i...n),那么i向num值在(low, num[i])内的所有在i之前的地方都右边,可以用一个按num值维护的线段树来查询区间内最小的下标值,即可知道是否有边。

DFS时,每访问一个点,就把这个点从两个线段树中删除,保证以后不会再访问到。最终对染色方案进行判断,看是否合法即可。

 

代码

 

  1 #include <bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 const int N = 2005;
  6 
  7 int n, num[N];
  8 
  9 int low[N], col[N];
 10 
 11 int hd[N], to[N], nt[N], tot;
 12 
 13 void addEdge(int x, int y)
 14 {
 15     nt[++tot] = hd[x]; to[tot] = y; hd[x] = tot;
 16     nt[++tot] = hd[y]; to[tot] = x; hd[y] = tot;
 17 }
 18 
 19 bool dfs(int u, int c)
 20 {
 21     if (col[u] != -1)
 22         return col[u] != c;
 23 
 24     col[u] = c;
 25     
 26     for (int i = hd[u]; i; i = nt[i])
 27         if (dfs(to[i], c ^ 1))return true;
 28         
 29     return false;
 30 }
 31 
 32 int stk1[N], tot1;
 33 int stk2[N], tot2;
 34 int ans[N], cnt, t(1);
 35 
 36 void pop(void)
 37 {
 38     if (tot1 && stk1[tot1] == t)
 39         { ans[++cnt] = 1, --tot1, ++t; pop(); }
 40     if (tot2 && stk2[tot2] == t)
 41         { ans[++cnt] = 3, --tot2, ++t; pop(); }
 42 }
 43 
 44 void putAns(void)
 45 {
 46     for (int i = 1; i <= n; ++i)
 47     {
 48         pop();
 49         
 50         switch (col[i])
 51         {
 52             case 0: 
 53             {
 54                 stk1[++tot1] = num[i];
 55                 ans[++cnt] = 0;
 56                 break;
 57             }
 58             case 1:
 59             {
 60                 stk2[++tot2] = num[i];
 61                 ans[++cnt] = 2;
 62                 break;
 63             }
 64         }
 65     }
 66     
 67     pop();
 68     
 69     for (int i = 1; i <= cnt; ++i)
 70         printf("%c ", 'a' + ans[i]);
 71 }
 72 
 73 signed main(void)
 74 {
 75     scanf("%d", &n);
 76     
 77     for (int i = 1; i <= n; ++i)
 78         scanf("%d", num + i);
 79         
 80     low[n] = num[n];
 81         
 82     for (int i = n; i >= 2; --i)
 83         low[i - 1] = min(num[i], low[i]);
 84         
 85     for (int i = 1; i < n; ++i)
 86         for (int j = 1 + i; j <= n; ++j)
 87             if (num[i] < num[j] && num[i] > low[j])
 88                 addEdge(i, j);
 89                 
 90     bool flag = true;
 91     
 92     memset(col, -1, sizeof(col));
 93     
 94     for (int i = 1; i <= n; ++i)
 95         if (col[i] == -1)if (dfs(i, 0))
 96             { flag = false; break; }
 97             
 98     if (flag)
 99         putAns();
100     else
101         puts("0");
102 }
双栈排序.cpp

 

  1 #include <bits/stdc++.h>
  2 
  3 template <class Int>
  4 Int min(const Int &a, const Int &b)
  5 {
  6     return a < b ? a : b;
  7 }
  8 
  9 template <class Int>
 10 Int max(const Int &a, const Int &b)
 11 {
 12     return a > b ? a : b;
 13 }
 14 
 15 #define N 1000005
 16 
 17 struct Data
 18 {
 19     int val;
 20     int pos;
 21     
 22     Data(void) {};
 23     Data(int v, int p)
 24     {
 25         val = v;
 26         pos = p;
 27     }
 28     
 29     friend bool operator < 
 30     (const Data &a, const Data &b)
 31     {
 32         return a.val < b.val;
 33     }
 34     
 35     friend bool operator > 
 36     (const Data &a, const Data &b)
 37     {
 38         return a.val > b.val;
 39     }
 40 };
 41 
 42 struct Node
 43 {
 44     int lt;
 45     int rt;
 46     Data min;
 47     Data max;
 48 };
 49 
 50 struct SegTree
 51 {
 52     Node tr[N << 2];
 53     
 54     void build(int p, int l, int r)
 55     {
 56         Node &t = tr[p];
 57         
 58         t.lt = l;
 59         t.rt = r;
 60         
 61         t.min = Data(N, 0);
 62         t.max = Data(0, 0);
 63         
 64         if (l ^ r)
 65         {
 66             int mid = (l + r) >> 1;
 67             
 68             build(p << 1, l, mid);
 69             build(p << 1 | 1, mid + 1, r);
 70         }
 71     }
 72     
 73     Data queryMin(int p, int l, int r)
 74     {
 75         if (l > r)
 76             return Data(N, 0);
 77         
 78         Node &t = tr[p];
 79         
 80         if (t.lt == l && t.rt == r)
 81             return t.min;
 82             
 83         int mid = (t.lt + t.rt) >> 1;
 84         
 85         if (r <= mid)
 86             return queryMin(p << 1, l, r);
 87         else if (l > mid)
 88             return queryMin(p << 1 | 1, l, r);
 89         else
 90             return min(
 91                 queryMin(p << 1, l, mid), 
 92                 queryMin(p << 1 | 1, mid + 1, r)
 93             );
 94     }
 95     
 96     Data queryMax(int p, int l, int r)
 97     {
 98         if (l > r)
 99             return Data(0, 0);
100         
101         Node &t = tr[p];
102         
103         if (t.lt == l && t.rt == r)
104             return t.max;
105             
106         int mid = (t.lt + t.rt) >> 1;
107         
108         if (r <= mid)
109             return queryMax(p << 1, l, r);
110         else if (l > mid)
111             return queryMax(p << 1 | 1, l, r);
112         else
113             return max(
114                 queryMax(p << 1, l, mid),
115                 queryMax(p << 1 | 1, mid + 1, r)
116             );
117     }
118     
119     void change(int p, int pos, Data val)
120     {
121         Node &t = tr[p];
122         
123         if (t.lt == t.rt)
124             t.min = t.max = val;
125         else
126         {
127             int mid = (t.lt + t.rt) >> 1;
128             
129             if (pos <= mid)
130                 change(p << 1, pos, val);
131             else
132                 change(p << 1 | 1, pos, val);
133                 
134             t.min = min(tr[p << 1].min, tr[p << 1 | 1].min);
135             t.max = max(tr[p << 1].max, tr[p << 1 | 1].max);
136         }
137     }
138 };
139 
140 int n;
141 int num[N];
142 int low[N];
143 int pre[N];
144 
145 SegTree A;
146 SegTree B;
147 
148 int color[N];
149 
150 bool dfs(int u, int c)
151 {
152     if (color[u] != -1)
153         return color[u] != c;
154 
155     color[u] = c;        
156     
157     A.change(1, u, Data(0, 0));
158     B.change(1, num[u], Data(N, 0));
159     
160 sta:Data a = A.queryMax(1, u + 1, pre[num[u] - 1]);
161     
162     if (a.pos && a.val > num[u])
163     {
164         if (dfs(a.pos, color[u] ^ 1))
165             return true;
166             
167         goto sta;
168     }
169     
170 stb:Data b = B.queryMin(1, low[u] + 1, num[u] - 1);
171     
172     if (b.pos && b.val < u)
173     {
174         if (dfs(b.pos, color[u] ^ 1))
175             return true;
176             
177         goto stb;
178     }
179     
180     return false;
181 }
182 
183 int bit[2][N];
184 
185 int lowbit(int x)
186 {
187     return x & -x;
188 }
189 
190 void add(int *b, int p)
191 {
192     while (p <= n)
193         ++b[p], p += lowbit(p);
194 }
195 
196 int qry(int *b, int p)
197 {
198     int r = 0;
199     
200     while (p)
201         r += b[p], p -= lowbit(p);
202         
203     return r;
204 }
205 
206 signed main(void)
207 {
208     scanf("%d", &n);
209     
210     for (int i = 1; i <= n; ++i)
211         scanf("%d", num + i);
212     
213     memset(low, 0x3f, sizeof(low));
214     
215     for (int i = n; i >= 1; --i)
216         low[i] = min(num[i], low[i + 1]);
217         
218     for (int i = 1; i <= n; ++i)
219         pre[low[i]] = max(pre[low[i]], i);
220         
221     for (int i = 1; i <= n; ++i)
222         pre[i] = max(pre[i], pre[i - 1]);
223         
224     A.build(1, 1, n);
225     B.build(1, 1, n);
226     
227     for (int i = 1; i <= n; ++i)
228         A.change(1, i, Data(num[i], i));
229         
230     for (int i = 1; i <= n; ++i)
231         B.change(1, num[i], Data(i, i));
232         
233     memset(color, -1, sizeof(color));
234         
235     for (int i = 1; i <= n; ++i)
236         if (color[i] == -1)if (dfs(i, 0))
237             return puts("NIE"), 0;
238             
239     memset(bit, 0, sizeof(bit));
240             
241     for (int i = 1; i <= n; ++i)
242     {
243         if (qry(bit[color[i]], num[i] - 1) > qry(bit[color[i]], low[i]))
244             return puts("NIE"), 0;
245         else add(bit[color[i]], num[i]);
246     }
247             
248     puts("TAK");    
249         
250     for (int i = 1; i < n; ++i)
251         printf("%d ", ++color[i]);
252     
253     printf("%d\n", ++color[n]);
254 }
BZOJ_2080.cpp

 

@Author: YouSiki

posted @ 2016-11-14 19:21  YouSiki  阅读(759)  评论(0编辑  收藏  举报