题解 P3497 【[POI2010]KOL-Railway】
noip双栈排序加强版。
如果存在k使得ak<ai<aj且k>j>i,那么i,j不能入一个栈。
i<->j连一条边,之后跑二分图染色,优先给小的染黑色,表示进第一个栈。
我们可以预处理m[i]=min{a[i+1..n]}
对每个j,找ai<aj且ai>m[j]的。
然而我们不能把边都连出来,因为会是n^2。
我们想办法只连出一些生成树,染色之后模拟判断一下行不行。
方法就是每连了两个块就并成一个块,并且用可并堆维护块内最小ai。
因为m是单调增的,如果最小ai<=m,就弹出。
之后我们再用一个堆维护所有块里面最小ai最小的块,每次取出,如果满足ai<aj就连边,合并。
时间nlogn。
(好久没打堆了233)
#include<cstdio>
#include<algorithm>
using std::swap;
#define ch_top 10000000
char ch[ch_top],*now_w=ch-1;
#define print(x) *++now_w=x;
#define chmin(x,y) {if(x>y)x=y;}
#define N 101000
int a[N],m[N];//m[i]=i->n min
int t[N];
struct edge
{
int to,next;
}l[10000000];int e;
#define add_e(x,y) l[++e]=(edge){y,t[x]};t[x]=e;
bool vis[N],col[N];//col[i]=1 第一个栈
int q1[N],t1,q2[N],t2;
int n;
int head[N],next[N];
int h[N<<1],top;
void dfs(int x,bool now)
{
if (vis[x])
{
if (col[x]!=now) {puts("NIE");exit(0);}
}
else
{
vis[x]=1;col[x]=now;
for (int i=t[x];i;i=l[i].next) dfs(l[i].to,now^1);
}
}
void move()
{
for (int i=1,j;(j=i<<1)<=top;)
{
if (j<top&&a[h[j]]>a[h[j+1]]) ++j;
if (a[h[i]]<a[h[j]]) break ;
swap(h[i],h[j]);i=j;
}
}
void push(int x)
{
h[++top]=x;
for (int i=top,j;i>1;)
{
if (a[h[i]]>=a[h[j=i>>1]]) break;
swap(h[i],h[j]);i=j;
}
}
void merge(int &x,int y)
{
if (a[x]<a[y])
{
next[y]=head[x];head[x]=y;
}
else
{
next[x]=head[y];head[y]=x;
x=y;
}
}
void merges(int &x)
{
int y=next[x],r;
while (y)
{
r=next[y];
merge(x,y);
y=r;
}
next[x]=0;
}
int main()
{
freopen("1.in","r",stdin);
int i,j;
scanf("%d",&n);
for (i=1;i<=n;++i) {scanf("%d",a+i);m[i]=a[i];}
for (i=n;--i;) chmin(m[i],m[i+1])
h[top=1]=1;
a[0]=N+1;
m[n+1]=N;
int p;
for (i=2;i<=n;++i)
{
int rt=i;
for (;a[p=h[1]]<a[i];)
{
while (a[p]<=m[i+1])
merges(p=head[p]);
if(a[p]<a[i]) {add_e(i,p);add_e(p,i);merge(rt,p);h[1]=h[top--]; }
else h[1]=p;
move();
}
push(rt);
}
int now=1;
print('T') print('A') print('K') print('\n')
for (i=1;i<=n;++i)
{
if (!vis[i]) dfs(i,1);
if (col[i]) {q1[++t1]=i;print('1') }
else {q2[++t2]=i;print('2') }
print(' ')
while (a[q1[t1]]==now||a[q2[t2]]==now)
{
if (a[q1[t1]]==now++) { --t1; }
else { --t2; }
}
}
if (now<=n) puts("NIE");
else fwrite(ch,1,now_w-ch,stdout);
}