[CQOI 2014] 排序机械臂

[CQOI 2014] 排序机械臂_第1张图片

看完此题数据范围n<=100000,就知道与模拟无缘了(不知道是脑残还是怎样,第一次做的时候由于只剩下半个小时,于是匆匆写了个模拟,然后光荣的爆0了,原因很简单,我把题目看错了T_T)

就是这句话:如果有高度相同的物品,必须保证他们排序后与初始的相对位置关系相同。

被样例2骗了,SB的写了一个错误的DP,然后由于splay太长时间没写,所以……

对于这个限制条件,我给每个点加上了时间标记dnf(这当然不是tarjan……随手写写而已)

然后加上三个与DP相关的域:mi,ti,pos,分别表示当前区间可以取到的最小值、该最小值所对应的时间戳,要达到该最小值该怎么走(pos=0时为本身,pos=1时向左走,pos=2时向右走),然后DP方程就可以随便写了,另外涉及反转区间加上rev域,这个真是做烂了,没什么好说的。

好不容易把splay写完了,结果TLE(我开始质疑这台电脑了),无奈之下,将初始的链建成一棵二叉树,还是TLE,然后只好到bzoj上提交,两份代码都AC了,相差几十毫秒(坑爹啊!)

这一次偷懒没写自顶向下的splay,写的是自底向上的,感觉WJMZBMR的思路太神奇了,splay那么短(十分感动……)

其他就没有什么好说了,上代码:

#include 
#include 
#include 
#include 
#include 
#include 
#define setc(x,s,d) (p[c[x][d]=s]=x,update(x))
#define root(x) (!p[x])
#define ch(x) (c[p[x]][1]==x)
#define _rev(x) (rev[x]^=1)
#define MaxN 100010
using namespace std;
const int INF=~0U>>2;
int n,t,x,ans;
int a[MaxN],c[MaxN][2],p[MaxN],sz[MaxN];
int pos[MaxN],mi[MaxN],dfn[MaxN],ti[MaxN];
bool rev[MaxN];
map m;
map::iterator iter;
inline void push(const int &x)
{
	if(!x) return;
	if(rev[x])
	{
		swap(c[x][0],c[x][1]);
		pos[x]=(3-pos[x])%3;
		if(c[x][0]) _rev(c[x][0]);
		if(c[x][1]) _rev(c[x][1]);
		rev[x]=0;
	}
}
inline void update(const int &x)
{
	if(!x) return;
	sz[x]=sz[c[x][0]]+1+sz[c[x][1]];
	mi[x]=a[x],pos[x]=0,ti[x]=dfn[x];
	for(int i=0;i<2;i++)
		if(mi[c[x][i]]r) return 0;
	int m=(l+r)>>1;
	if(l!=r)
		p[c[m][0]=build(l,m-1)]=m,
		p[c[m][1]=build(m+1,r)]=m;
	update(m);
	return m;
}

inline void init()
{
	cin>>n;
	mi[0]=dfn[0]=ti[0]=INF;
	a[n+1]=mi[n+1]=dfn[n+1]=ti[n+1]=INF;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		iter=m.find(a[i]);
		if(iter==m.end())
			m.insert(make_pair(a[i],0));
		else dfn[i]=++(iter->second);
//		setc(i,i-1,0);
	}
	t=build(1,n+1);
//	t=n;
}
int main()
{
	freopen("sort.in","r",stdin);
	freopen("sort.out","w",stdout);
	init();
	work();
	return 0;
}


你可能感兴趣的:(平衡树)