BZOJ2080[Poi2010] Railway
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)
Solution:
这题就是NOIP2008双栈排序的加强版,时间复杂度被从
O(n2)
压缩到了
O(nlogn)
以内。这就是网上根本找不到题解的原因?
设
fin[i]
表示处理
i
的时候
于是我们把这些权值的区间放到set里,每次对在
好好想了想好像复杂度并不能保证 O(nlogn) ,这取决于set中的元素个数。
注:由于 fin 数组单调递增,如果set的begin处小于 fin 就可以直接erase掉。这里有一个点:不存在跨过 fin 的区间。
因为set中的区间在栈中是连续的,如果 fin 值在区间中间,那么实际上 fin 值可以直接被推到这个区间的末尾。
证毕。
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<set>
#include<vector>
#define M 100005
#define mp make_pair
#define _st ->first
#define _ed ->second
using namespace std;
int A[M],fin[M],F[M<<1],col[M<<1],ans[M];
bool mark[M];
vector<int>putin;
set<pair<int,int> >Q;
int findfa(int x){
if(F[x]==x)return x;
else return F[x]=findfa(F[x]);
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&A[i]);
int nxt=0;
for(int i=1;i<=n;i++){
mark[A[i]]=true;
while(mark[nxt+1])nxt++;
fin[i]=nxt;
}
for(int i=1;i<=n*2;i++)
F[i]=i;
for(int i=1;i<=n;i++){
while(!Q.empty()&&Q.begin()_st<=fin[i])Q.erase(Q.begin());
if(!Q.empty()&&Q.begin()_st<A[i]){
set<pair<int,int> >::iterator it,it1;
int fa=findfa(Q.begin()_st),fb=findfa(Q.begin()_st+n);
for(it=Q.begin();it!=Q.end()&&it _st<A[i];it++){
int ffa=findfa(it _st),ffb=findfa(it _st+n);
if(ffa==fb||ffb==fa){
puts("NIE");
return 0;
}else{
F[ffa]=fa;
F[ffb]=fb;
}
}
putin.clear();
for(it=Q.begin();it!=Q.end()&&it _st<A[i];it++){//诡异的合并操作
if(it==Q.begin()){
putin.push_back(it _st);
putin.push_back(it _ed);
}else{
if(putin[putin.size()-1]+1==it _st)putin[putin.size()-1]=it _ed;
else{
putin.push_back(it _st);
putin.push_back(it _ed);
}
}
}
for(it=Q.begin();it!=Q.end()&&it _st<A[i];){
it1=it++;
Q.erase(it1);
}
for(int j=1;j<putin.size();j+=2)
Q.insert(mp(putin[j-1],putin[j]));
F[A[i]]=fb;F[A[i]+n]=fa;
}
Q.insert(mp(A[i],A[i]));
}
puts("TAK");
for(int i=1;i<=n;i++){
int fa=findfa(i),fb=findfa(i+n);
if(!col[fa]||col[fb]==-1&&col[fa]==1){
col[fa]=1;
ans[i]=1;
col[fa+((fa>n)?-n:n)]=-1;
}else{
col[fb]=1;
ans[i]=2;
col[fb+((fb>n)?-n:n)]=-1;
}
}
for(int i=1;i<=n;i++)
printf("%d%c",ans[A[i]],(i==n)?'\n':' ');
return 0;
}
其他大犇们都在写稳定的 O(nlogn) 算法。蒟蒻浑身发抖…