zoukankan      html  css  js  c++  java
  • 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
    ", ++color[n]);
    254 }
    BZOJ_2080.cpp

    @Author: YouSiki

  • 相关阅读:
    【转】Chrome 控制台不完全指南
    AngularJS 之 Factory vs Service vs Provider【转】
    【转】NuGet.org 无法访问的解决方法
    jquery easyui 1.4.1 验证时tooltip 的位置调整
    jquery easyui 1.4.1 API( CHM版)
    扩展 easyui-tabs 插件 关闭标签页方法
    easyui layout 折叠后显示标题
    easyui 中Datagrid 控件在列较多且无数据时,列显示不全的解决方案
    为easyui datagrid 添加上下方向键移动
    Android布局实现圆角边框
  • 原文地址:https://www.cnblogs.com/yousiki/p/6063068.html
Copyright © 2011-2022 走看看