BZOJ 2080: [Poi2010]Railway 双栈排序
2080: [Poi2010]Railway
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 140 Solved: 35
[Submit][Status][Discuss]
Description
一个铁路包含两个侧线1和2,右边由A进入,左边由B出去(看下面的图片)
![](http://www.lydsy.com/JudgeOnline/images/2080.jpg)
有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
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)
TAK
1 1 2 1 (1号线进到侧线1,然后出来,3号进入侧线1,4号进入侧线2,2号进入侧线1,然后出来,接着3号出来,4号出来)
[样例输出2]
NIE (不可能。。No)
HINT
Source
分析
本题和 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时,每访问一个点,就把这个点从两个线段树中删除,保证以后不会再访问到。最终对染色方案进行判断,看是否合法即可。
代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
@Author: YouSiki