CQOI2014 排序机械臂

传送门

突然发现自己不大会维护位置这种题……学习了一下。

具体的操作还是使用\(fhq-treap\)实现。什么split,merge都一样。问题是如何求位置。

首先我们在读入的时候,保存每个节点的权值和下标,并且按照权值进行排序,同时把它插入到一棵\(fhq-treap\)中。

之后我们怎么查找一个节点所在的位置呢?其实我们相当于找这个节点的排名,也就是其前面有多少。但是这个无法简单的split之后去求解。不过因为\(fhq-treap\)的期望树高是log的,我们可以直接通过暴力跳父亲来计算答案。具体的方法就是,如果你是你父亲的右儿子,那么答案就加上你父亲的左儿子的size+1,之后继续暴力上跳即可。

然后注意在查询之前要走到父亲并且手动全部pushdown一遍。

看一下代码。

#include<bits/stdc++.h>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
#define I inline

using namespace std;
typedef long long ll;
const int M = 500005;

I int read()
{
    int ans = 0,op = 1;char ch = getchar();
    while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
    while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
    return ans * op; 
}

struct node
{
	int v,id;
	bool operator < (const node &g) const {return v < g.v || (v == g.v && id < g.id);}
}s[M];

struct tree
{
	int lc,rc,fa,size,rev,rk;
}t[M];

int n,root,top,sta[M];

I void rever(int x) {t[x].rev ^= 1,swap(t[x].lc,t[x].rc);}
I void pushup(int x) 
{
	t[x].size = t[t[x].lc].size + t[t[x].rc].size + 1;
	t[t[x].lc].fa = x,t[t[x].rc].fa = x;
}
I void pushdown(int x) 
{
	if(!t[x].rev) return;
	if(t[x].lc) rever(t[x].lc);
	if(t[x].rc) rever(t[x].rc);
	t[x].rev ^= 1;
}

int merge(int x,int y)
{
	if(!x || !y) return x | y;
	pushdown(x),pushdown(y);
	if(t[x].rk < t[y].rk) {t[x].rc = merge(t[x].rc,y),pushup(x);return x;}
	else {t[y].lc = merge(x,t[y].lc),pushup(y);return y;}
}

void splits(int u,int k,int &x,int &y)
{
	if(!u) {x = y = 0;return;}
	pushdown(u);
	if(t[t[u].lc].size >= k) y = u,splits(t[u].lc,k,x,t[u].lc);
	else x = u,splits(t[u].rc,k-t[t[u].lc].size-1,t[u].rc,y);
	pushup(u);
}

int kth(int u)
{
	sta[++top] = u;
	for(int i = u;t[i].fa;i = t[i].fa) sta[++top] = t[i].fa;
	while(top) pushdown(sta[top--]);
	int cur = t[t[u].lc].size;
	while(u) 
	{
		if(u == t[t[u].fa].rc) cur += t[t[t[u].fa].lc].size + 1;
		u = t[u].fa;
	}
	return cur + 1;
}

void Rever(int l,int r)
{
	int x,y,z;
	splits(root,r,x,y),splits(x,l-1,x,z);
	rever(z),root = merge(merge(x,z),y);
}

int main()
{ 
	srand(time(0));
	n = read();
	rep(i,1,n) s[i].v = read(),s[i].id = i,t[i].size = 1,t[i].rk = rand(),root = merge(root,i);
	sort(s+1,s+1+n);
	rep(i,1,n)
	{
		int k = kth(s[i].id);
		printf("%d ",k),Rever(i,k); 
	} 
	enter;
	return 0;
}
posted @ 2019-01-22 14:54  CaptainLi  阅读(196)  评论(0编辑  收藏  举报