BZOJ2080: [Poi2010]Railway

111 篇文章 0 订阅
14 篇文章 0 订阅
题目大意:数据范围10W的双栈排序..双栈排序是啥呢?给你一个序列和两个栈,每次你可以把序列头入到两个栈的任意一个,或者把两个栈的任意一个弹出到最终序列,最后要求最终序列是有序的,求一种字典序最小的入栈方案

感觉自己应该是写不明白...日后如果有兴趣再来填坑吧..
先附上多年以前 vfk写的题解,非常详细
再附上我的代码...

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define N 100010
using namespace std;
int a[N],fan[N],pre[N],L[N];
int l[N<<2],r[N<<2],h[N<<2],cnt;
struct ppp{int mx,mxb;}W[N<<2];
ppp operator +(const ppp &x,const ppp &y)
{
	ppp ret;
	ret.mx=max(x.mx,y.mx);
	if(x.mx>y.mx) ret.mxb=x.mxb;
	else ret.mxb=y.mxb;
	return ret;
}
void pup(int x)
{
	W[x]=W[x<<1]+W[x<<1|1];
}
void build(int now,int ll,int rr)
{
	l[now]=ll;r[now]=rr;
	cnt++;h[now]=cnt;
	if(ll==rr) 
	{
		W[now]=(ppp){a[ll],ll};
		return;
	}
	int mid=(ll+rr)>>1;
	build(now<<1,ll,mid);
	build(now<<1|1,mid+1,rr);
	pup(now);
}
int bef[N*30],nxt[N*30],w[N*30];
int S[N],T[N];
void change(int now,int ll,int rr,int v)
{
	if(l[now]==ll&&r[now]==rr)
	{
		cnt++;
		w[cnt]=v;
		nxt[cnt]=nxt[h[now]];
		bef[cnt]=h[now];
		bef[nxt[h[now]]]=cnt;
		nxt[h[now]]=cnt;
		return;
	}
	int mid=(l[now]+r[now])>>1;
	if(rr<=mid) change(now<<1,ll,rr,v);
	else if(ll>mid) change(now<<1|1,ll,rr,v);
	else change(now<<1,ll,mid,v),change(now<<1|1,mid+1,rr,v);
}
void change1(int now,int x)
{
	if(l[now]==r[now]) {W[now]=(ppp){0,0};return;}
	int mid=(l[now]+r[now])>>1;
	if(x<=mid) change1(now<<1,x);
	else change1(now<<1|1,x);
	pup(now);
}
int col[N];
void erase(int x)
{
	int i;
	change1(1,x);
	for(i=S[x];i<=T[x];i++)
	{
		bef[nxt[i]]=bef[i];
		nxt[bef[i]]=nxt[i];
	}
}
ppp check1(int now,int ll,int rr)
{
	if(ll==l[now]&&rr==r[now]) return W[now];
	int mid=(l[now]+r[now])>>1;
	if(rr<=mid) return check1(now<<1,ll,rr);
	else if(ll>mid) return check1(now<<1|1,ll,rr);
	else return check1(now<<1,ll,mid)+check1(now<<1|1,mid+1,rr);
}
int check(int now,int x)
{
	if(nxt[h[now]]&&w[nxt[h[now]]]<a[x]) return fan[w[nxt[h[now]]]];
	if(l[now]==r[now]) return -1;
	int mid=(l[now]+r[now])>>1;
	if(x<=mid) return check(now<<1,x);
	else return check(now<<1|1,x);
}
int getedge(int x)
{
	ppp tmp=check1(1,x,L[x]);
	if(tmp.mx>a[x]) return tmp.mxb;
	return check(1,x);
}
void dfs(int x,int c)
{
	col[x]=c;
	erase(x);
	while(1)
	{
		int y=getedge(x);
		if(y==-1) break;
		dfs(y,3-c);
	}
}
int n;
int s[3][N],t[3];
bool pcan()
{
	int i,j,x;
	for(i=1;i<=n;i++)
	{
		x=col[i];
		while(t[x]&&L[s[x][t[x]]]<=i) t[x]--;
		if(t[x]&&a[s[x][t[x]]]<a[i]) return puts("NIE"),false;
		t[x]++;s[x][t[x]]=i;
	}
	return puts("TAK"),true;
}
int main()
{
	scanf("%d",&n);
	int i,j,x,y;
	for(i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		fan[a[i]]=pre[a[i]]=i;
	}
	for(i=1;i<=n;i++)
	pre[i]=max(pre[i],pre[i-1]);
	for(i=1;i<=n;i++)
	L[fan[i]]=pre[i];
	build(1,1,n);
	for(i=n;i>=1;i--)
	{
		x=fan[i];
		S[x]=cnt+1;
		change(1,x,L[x],i);
		T[x]=cnt;
	}
	for(i=1;i<=n;i++)
	if(!col[i])
	dfs(i,1);
	if(pcan())
	{
		printf("%d",col[1]);
		for(i=2;i<=n;i++)
		printf(" %d",col[i]);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值