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

代码

 #include <bits/stdc++.h>

 using namespace std;

 const int N = ;

 int n, num[N];

 int low[N], col[N];

 int hd[N], to[N], nt[N], tot;

 void addEdge(int x, int y)
{
nt[++tot] = hd[x]; to[tot] = y; hd[x] = tot;
nt[++tot] = hd[y]; to[tot] = x; hd[y] = tot;
} bool dfs(int u, int c)
{
if (col[u] != -)
return col[u] != c; col[u] = c; for (int i = hd[u]; i; i = nt[i])
if (dfs(to[i], c ^ ))return true; return false;
} int stk1[N], tot1;
int stk2[N], tot2;
int ans[N], cnt, t(); void pop(void)
{
if (tot1 && stk1[tot1] == t)
{ ans[++cnt] = , --tot1, ++t; pop(); }
if (tot2 && stk2[tot2] == t)
{ ans[++cnt] = , --tot2, ++t; pop(); }
} void putAns(void)
{
for (int i = ; i <= n; ++i)
{
pop(); switch (col[i])
{
case :
{
stk1[++tot1] = num[i];
ans[++cnt] = ;
break;
}
case :
{
stk2[++tot2] = num[i];
ans[++cnt] = ;
break;
}
}
} pop(); for (int i = ; i <= cnt; ++i)
printf("%c ", 'a' + ans[i]);
} signed main(void)
{
scanf("%d", &n); for (int i = ; i <= n; ++i)
scanf("%d", num + i); low[n] = num[n]; for (int i = n; i >= ; --i)
low[i - ] = min(num[i], low[i]); for (int i = ; i < n; ++i)
for (int j = + i; j <= n; ++j)
if (num[i] < num[j] && num[i] > low[j])
addEdge(i, j); bool flag = true; memset(col, -, sizeof(col)); for (int i = ; i <= n; ++i)
if (col[i] == -)if (dfs(i, ))
{ flag = false; break; } if (flag)
putAns();
else
puts("");
}

双栈排序.cpp

 #include <bits/stdc++.h>

 template <class Int>
Int min(const Int &a, const Int &b)
{
return a < b ? a : b;
} template <class Int>
Int max(const Int &a, const Int &b)
{
return a > b ? a : b;
} #define N 1000005 struct Data
{
int val;
int pos; Data(void) {};
Data(int v, int p)
{
val = v;
pos = p;
} friend bool operator <
(const Data &a, const Data &b)
{
return a.val < b.val;
} friend bool operator >
(const Data &a, const Data &b)
{
return a.val > b.val;
}
}; struct Node
{
int lt;
int rt;
Data min;
Data max;
}; struct SegTree
{
Node tr[N << ]; void build(int p, int l, int r)
{
Node &t = tr[p]; t.lt = l;
t.rt = r; t.min = Data(N, );
t.max = Data(, ); if (l ^ r)
{
int mid = (l + r) >> ; build(p << , l, mid);
build(p << | , mid + , r);
}
} Data queryMin(int p, int l, int r)
{
if (l > r)
return Data(N, ); Node &t = tr[p]; if (t.lt == l && t.rt == r)
return t.min; int mid = (t.lt + t.rt) >> ; if (r <= mid)
return queryMin(p << , l, r);
else if (l > mid)
return queryMin(p << | , l, r);
else
return min(
queryMin(p << , l, mid),
queryMin(p << | , mid + , r)
);
} Data queryMax(int p, int l, int r)
{
if (l > r)
return Data(, ); Node &t = tr[p]; if (t.lt == l && t.rt == r)
return t.max; int mid = (t.lt + t.rt) >> ; if (r <= mid)
return queryMax(p << , l, r);
else if (l > mid)
return queryMax(p << | , l, r);
else
return max(
queryMax(p << , l, mid),
queryMax(p << | , mid + , r)
);
} void change(int p, int pos, Data val)
{
Node &t = tr[p]; if (t.lt == t.rt)
t.min = t.max = val;
else
{
int mid = (t.lt + t.rt) >> ; if (pos <= mid)
change(p << , pos, val);
else
change(p << | , pos, val); t.min = min(tr[p << ].min, tr[p << | ].min);
t.max = max(tr[p << ].max, tr[p << | ].max);
}
}
}; int n;
int num[N];
int low[N];
int pre[N]; SegTree A;
SegTree B; int color[N]; bool dfs(int u, int c)
{
if (color[u] != -)
return color[u] != c; color[u] = c; A.change(, u, Data(, ));
B.change(, num[u], Data(N, )); sta:Data a = A.queryMax(, u + , pre[num[u] - ]); if (a.pos && a.val > num[u])
{
if (dfs(a.pos, color[u] ^ ))
return true; goto sta;
} stb:Data b = B.queryMin(, low[u] + , num[u] - ); if (b.pos && b.val < u)
{
if (dfs(b.pos, color[u] ^ ))
return true; goto stb;
} return false;
} int bit[][N]; int lowbit(int x)
{
return x & -x;
} void add(int *b, int p)
{
while (p <= n)
++b[p], p += lowbit(p);
} int qry(int *b, int p)
{
int r = ; while (p)
r += b[p], p -= lowbit(p); return r;
} signed main(void)
{
scanf("%d", &n); for (int i = ; i <= n; ++i)
scanf("%d", num + i); memset(low, 0x3f, sizeof(low)); for (int i = n; i >= ; --i)
low[i] = min(num[i], low[i + ]); for (int i = ; i <= n; ++i)
pre[low[i]] = max(pre[low[i]], i); for (int i = ; i <= n; ++i)
pre[i] = max(pre[i], pre[i - ]); A.build(, , n);
B.build(, , n); for (int i = ; i <= n; ++i)
A.change(, i, Data(num[i], i)); for (int i = ; i <= n; ++i)
B.change(, num[i], Data(i, i)); memset(color, -, sizeof(color)); for (int i = ; i <= n; ++i)
if (color[i] == -)if (dfs(i, ))
return puts("NIE"), ; memset(bit, , sizeof(bit)); for (int i = ; i <= n; ++i)
{
if (qry(bit[color[i]], num[i] - ) > qry(bit[color[i]], low[i]))
return puts("NIE"), ;
else add(bit[color[i]], num[i]);
} puts("TAK"); for (int i = ; i < n; ++i)
printf("%d ", ++color[i]); printf("%d\n", ++color[n]);
}

BZOJ_2080.cpp

@Author: YouSiki

BZOJ 2080: [Poi2010]Railway 双栈排序的更多相关文章

  1. 虚拟化构建二分图(BZOJ2080 题解+浅谈几道双栈排序思想的题)

    虚拟化构建二分图 ------BZOJ2080 题解+浅谈几道双栈排序思想的题 本题的题解在最下面↓↓↓ 不得不说,第一次接触类似于双栈排序的这种题,是在BZOJ的五月月赛上. [BZOJ4881][ ...

  2. NOIP2008双栈排序[二分图染色|栈|DP]

    题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...

  3. noip2008 双栈排序

    题目描述 Description \(Tom\)最近在研究一个有趣的排序问题.如图所示,通过\(2\)个栈\(S_1\)和\(S_2\),\(Tom\)希望借助以下\(4\)种操作实现将输入序列升序排 ...

  4. 双栈排序(codevs 1170)

    题目描述 Description Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈 ...

  5. #include <NOIP2008 Junior> 双栈排序 ——using namespace wxl;

    题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...

  6. [NOIP2008] 提高组 洛谷P1155 双栈排序

    题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...

  7. 【NOIP2008】双栈排序

    感觉看了题解还是挺简单的,不知道当年chty同学为什么被卡了呢么久--所以说我还是看题解了 原题: Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将 ...

  8. 双栈排序(codevs 1170)题解

    [问题描述] Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈 ...

  9. Noip2008双栈排序

    [问题描述] 用两个栈使一个1...n的排列变得有序.一共有四个操作: A.stack1.push() 读入一个放入栈一 B.stack1.pop() 弹出栈一放入输出序列 C.stack2.push ...

随机推荐

  1. window10 安装出现the error code is 2503错误的解决方法

    window10 安装出现the error code is 2503错误的解决方法:  设置 C:\WINDOWS\TEMP的权限

  2. Ubuntu终端命令行不显示颜色

    在网上找到的一个有效方案是在.bash_profile 中增加颜色定义 export LS_COLORS='di=01;35:ln=01;36:pi=40;33:so=01;35:do=01;35:b ...

  3. SQL Server存储过程中使用表值作为输入参数示例

    这篇文章主要介绍了SQL Server存储过程中使用表值作为输入参数示例,使用表值参数,可以不必创建临时表或许多参数,即可向 Transact-SQL 语句或例程(如存储过程或函数)发送多行数据,这样 ...

  4. 如何让jboss eap 6.2+ 的多个war应用共享 jar 包?

    weblogic有一个很贴心的功能,允许把多个war应用共同依赖的jar包,打包一个单独的war,以libary方式部署,然后各应用在weblogic.xml里声明引用该libary即可,这样可大大减 ...

  5. mac上开启ftp

    开启 sudo -s launchctl load -w /System/Library/LaunchDaemons/ftp.plist 关闭 sudo -s launchctl unload -w ...

  6. Spring TestContext测试框架搭建

    同样是测试,JUnit和Spring TestContext相比,Spring TestContext优势如下: 1.Spring TestContext可以手动设置测试事务回滚,不破坏数据现场 2. ...

  7. Hadoop简单安装配置

    Hadoop开始设计以Linux平台为运行目标,所以这里推荐在Linux发行版比如Ubuntu进行安装,目前已经有Hadoop for Windows出来,大家自行搜下文章. Hadoop运行模式分为 ...

  8. Orchard搜索与索引

    Orchard提供了索引与搜索的功能.开启Indexing属性可实现索引功能,伴随着一个特定的索引执行(默认包含基础搜索引擎).除了Indexing和Search提供查询索引的功能外(通过关键字或使用 ...

  9. ModernUI教程:处理内容导航事件

    Modern UI包含了一个机遇uri的内容导航框架用来处理区域加载.卸载和处理访问记录页面间的导航. 如果你希望你的页面具有这些处理事件,你需要继承一个IContent接口,该接口位于FirstFl ...

  10. IT人员如何保护视力

    最近感觉眼比较难受,有点干,估计是因为用上老婆淘汰的iPhone5C后屏幕太小,而我又是一个手机瘾重点患者的原因.为了保持自己5.0+的视力,做了以下工作,分享给各位朋友: Win7电脑将字体放大到1 ...