【fhqtreap】航空管制

飞机因为航空管制晚点了一个多小时,于是正好学习一下fhq介绍过的treap...

poj2352

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
int l[200000],r[200000],s[2000000],w[200000],x[200000],y[200000];
int ss,root,n,ans[200000];
bool random(double p)
{
	return (double)rand()/RAND_MAX<p;
}
void print(int x)
{
	if (!x) return ;
	cout<<x<<' '<<l[x]<<' '<<r[x]<<endl;
	print(l[x]),print(r[x]);
}
int ori(int x)
{
	++ss,l[ss]=r[ss]=0;
	w[ss]=x,s[ss]=1;
	return ss;
}
void updata(int x)
{
	s[x]=s[l[x]]+1+s[r[x]];
}
int merge(int x,int y)
{
	if (!x) return y;
	if (!y) return x;
	if (random((double)s[x]/(s[x]+s[y]))) {
		r[x]=merge(r[x],y),updata(x);
		return x;
	}
	l[y]=merge(x,l[y]),updata(y);
	return y;
}
void split(int root,int k,int &a,int &b)
{
	if (!root) {
		a=b=0;
		return ;
	}
	if (w[root]>k) {								 
		int p,q;
		split(l[root],k,p,q);
		l[root]=0,updata(root);
		a=p,b=merge(q,root);
		return ;
	}
	int p,q;													//保证根节点被选 
	split(r[root],k,p,q);
	r[root]=0,updata(root);
	a=merge(root,p),b=q;
	return ;
}
int ask(int x)
{
	int a,b;
	split(root,x,a,b);
	int ans=s[a];
	root=merge(a,b);
	return ans;
}
int main()
{
	freopen("input.txt","r",stdin);
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d%d",&x[i],&y[i]);
	root=ss=0;
	for (int i=1;i<=n;i++) {
		int sum=ask(x[i]);
		ans[sum]++;
		int a,b;
		split(root,x[i],a,b);
		root=ori(x[i]);
		root=merge(a,root),root=merge(root,b);
	}
	for (int i=0;i<n;i++) printf("%d\n",ans[i]);
	return 0;
}

poj3580

上飞机前没调出来...

用叉姐的rand函数tle了,原因是值域只有32767,但是即便扩大范围也用了1900+ms,而黄哥的程序不但各种指针,stl,rand函数值域也只有32767还比我要快,难道真的是数组寻址太慢了不成...不过数据范围应该没那么大

值得一提的是我以前同样是数组实现的splay也比这个treap快的多,虽然说用这个treap处理某些操作非常方便...

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <ctime>
const int oo=1073741819;	
const int Rand_Max=2147483647;
using namespace std;
int l[250000],r[250000],w[250000],s[250000],Min[250000];
int Ad[250000],Sw[250000];
int root,ss,n,m;
void print(int x)
{
	if (!x) return ;
	cout<<x<<' '<<l[x]<<' '<<r[x]<<endl;
	print(l[x]);
	print(r[x]);
}
inline int ran()
{
	static int x = 1;
	x += (x << 2) + 1;
	return x & 2147483647;
}

bool random(double p)
{
	return (double) (ran())/Rand_Max < p;
}
int ori(int x)
{
	++ss,l[ss]=r[ss]=0;
	w[ss]=x,s[ss]=1,Min[ss]=x;
	Ad[ss]=0,Sw[ss]=0;
	return ss;
}
void add(int x,int W)
{
	if (!x) return ;
	w[x]+=W,Ad[x]+=W,Min[x]+=W;
}
void swap(int x)
{
	if (!x) return ;
	int e;
	e=l[x],l[x]=r[x],r[x]=e;
	Sw[x]^=1;
}
void updata(int x)
{
	if (!x) return ;
	s[x]=s[l[x]]+s[r[x]]+1;
	Min[x]=min(Min[l[x]],min(Min[r[x]],w[x]));
}
void pushdown(int x)
{
	if (!x) return ;
	if (Ad[x]) {
		add(l[x],Ad[x]),add(r[x],Ad[x]);
		Ad[x]=0;
	}
	if (Sw[x]) {
		swap(l[x]),swap(r[x]);
		Sw[x]=0;
	}
	updata(x);
}
int merge(int x,int y)
{
	if (!x) return y;
	if (!y) return x;
	//if (random((double)s[x]/(s[x]+s[y]))) {
	//if (w[x]<w[y]) {
	if (ran()%(s[x]+s[y])<s[x]) {
		pushdown(x);
		r[x]=merge(r[x],y);
		updata(x);
		return x;
	}
	pushdown(y);
	l[y]=merge(x,l[y]);
	updata(y);
	return y;
}
void split(int x,int k,int &a,int &b)
{
	if (!x) {
		a=b=0;
		return ;
	}
	pushdown(x);
	if (s[l[x]]>=k) {
		int p,q;
		split(l[x],k,p,q);
		l[x]=0,updata(x);
		a=p,b=merge(q,x);
		return ;
	}
	int p,q;
	split(r[x],k-(s[l[x]]+1),p,q);
	r[x]=0,updata(x);
	a=merge(x,p),b=q;
	return ;
}
int main()
{
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
	scanf("%d",&n);
	root=ss=0,Min[0]=oo,s[0]=0,w[0]=oo;
	for (int i=1;i<=n;i++) {
		int x;
		scanf("%d",&x);
		int y=ori(x);
		root=merge(root,y);
	}
	scanf("%d",&m);
	char ch[200];
	//print(root);
	for (int i=1;i<=m;i++) {
		scanf("%s",ch+1);
		if ('A'==ch[1]) {
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			int a,b,c,d;
			split(root,x-1,a,b);
			split(b,y-x+1,c,d);
			add(c,z);
			root=merge(a,merge(c,d));
		}
		else if ('R'==ch[1] && 'E'==ch[4]) {
			int x,y;
			scanf("%d%d",&x,&y);
			int a,b,c,d;
			split(root,x-1,a,b);
			split(b,y-x+1,c,d);
			swap(c);
			root=merge(a,merge(c,d));
		}
		else if ('R'==ch[1] && 'O'==ch[4]) {
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			//if ((z>(y-x+1))) continue;
			z%=(y-x+1);
			int a,b,c,d,e,f;
			split(root,x-1,a,b);
			split(b,y-x+1,c,d);
			split(c,(y-x+1)-z,e,f);
			root=merge(a,merge(f,merge(e,d)));
		}
		else if ('I'==ch[1]) {
			int x,y;
			scanf("%d%d",&x,&y);
			int p=ori(y);
			int a,b;
			split(root,x,a,b);
			root=merge(a,merge(p,b));
		}
		else if ('D'==ch[1]) {
			int x;
			scanf("%d",&x);
			int a,b,c,d;
			split(root,x-1,a,b);
			split(b,1,c,d);
			root=merge(a,d);
		}
		else if ('M'==ch[1]) {
			int x,y;
			scanf("%d%d",&x,&y);
			int a,b,c,d;
			split(root,x-1,a,b);
			split(b,y-x+1,c,d);
			int ans=Min[c];
			root=merge(a,merge(c,d));
			printf("%d\n",ans);
		}
	}
	cout<<clock()<<endl;
	return 0;
} 


update 2014.4.14

去掉了一个无用的updata,时间减少了100ms,又去掉了split的两个merge,时间瞬间减少了400+ms

果然细节对常数的影响巨大,不过split的两个merge确实是没有必要的,但是叉姐的板子里面有...

update 2014.5.11 

其实我也不知道去掉split的merge会不会导致树高不是log= =

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <ctime>
const int oo=1073741819;	
const int Rand_Max=1073741819;
using namespace std;
int l[250000],r[250000],w[250000],s[250000],Min[250000];
int Ad[250000],Sw[250000];
int root,ss,n,m;
void print(int x)
{
	if (!x) return ;
	cout<<x<<' '<<l[x]<<' '<<r[x]<<endl;
	print(l[x]);
	print(r[x]);
}
inline int ran()
{
	static int x = 1;
	x += (x << 2) + 1;
	return x & 1073741819;
}

bool random(double p)
{
	return (double) (ran())/Rand_Max < p;
}
int ori(int x)
{
	++ss,l[ss]=r[ss]=0;
	w[ss]=x,s[ss]=1,Min[ss]=x;
	Ad[ss]=0,Sw[ss]=0;
	return ss;
}
void add(int x,int W)
{
	if (!x) return ;
	w[x]+=W,Ad[x]+=W,Min[x]+=W;
}
void swap(int x)
{
	if (!x) return ;
	int e;
	e=l[x],l[x]=r[x],r[x]=e;
	Sw[x]^=1;
}
void updata(int x)
{
	if (!x) return ;
	s[x]=s[l[x]]+s[r[x]]+1;
	Min[x]=min(Min[l[x]],min(Min[r[x]],w[x]));
}
void pushdown(int x)
{
	if (!x) return ;
	if (Ad[x]) {
		add(l[x],Ad[x]),add(r[x],Ad[x]);
		Ad[x]=0;
	}
	if (Sw[x]) {
		swap(l[x]),swap(r[x]);
		Sw[x]=0;
	}
	//updata(x);
}
int merge(int x,int y)
{
	if (!x) return y;
	if (!y) return x;
	//if (random((double)s[x]/(s[x]+s[y]))) {
	//if (w[x]<w[y]) {
	if (ran()%(s[x]+s[y])<s[x]) {
		pushdown(x);
		r[x]=merge(r[x],y);
		updata(x);
		return x;
	}
	pushdown(y);
	l[y]=merge(x,l[y]);
	updata(y);
	return y;
}
void split(int x,int k,int &a,int &b)
{
	if (!x) {
		a=b=0;
		return ;
	}
	pushdown(x);
	if (s[l[x]]>=k) {
		int p,q;
		split(l[x],k,p,q);
		l[x]=q,updata(x);
		a=p,b=x;
		return ;
	}
	int p,q;
	split(r[x],k-(s[l[x]]+1),p,q);
	r[x]=p,updata(x);
	a=x,b=q;
	return ;
}
int main()
{
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
	scanf("%d",&n);
	root=ss=0,Min[0]=oo,s[0]=0,w[0]=oo;
	for (int i=1;i<=n;i++) {
		int x;
		scanf("%d",&x);
		int y=ori(x);
		root=merge(root,y);
	}
	scanf("%d",&m);
	char ch[200];
	//print(root);
	for (int i=1;i<=m;i++) {
		scanf("%s",ch+1);
		if ('A'==ch[1]) {
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			int a,b,c,d;
			split(root,x-1,a,b);
			split(b,y-x+1,c,d);
			add(c,z);
			root=merge(a,merge(c,d));
		}
		else if ('R'==ch[1] && 'E'==ch[4]) {
			int x,y;
			scanf("%d%d",&x,&y);
			int a,b,c,d;
			split(root,x-1,a,b);
			split(b,y-x+1,c,d);
			swap(c);
			root=merge(a,merge(c,d));
		}
		else if ('R'==ch[1] && 'O'==ch[4]) {
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			//if ((z>(y-x+1))) continue;
			z%=(y-x+1);
			int a,b,c,d,e,f;
			split(root,x-1,a,b);
			split(b,y-x+1,c,d);
			split(c,(y-x+1)-z,e,f);
			root=merge(a,merge(f,merge(e,d)));
		}
		else if ('I'==ch[1]) {
			int x,y;
			scanf("%d%d",&x,&y);
			int p=ori(y);
			int a,b;
			split(root,x,a,b);
			root=merge(a,merge(p,b));
		}
		else if ('D'==ch[1]) {
			int x;
			scanf("%d",&x);
			int a,b,c,d;
			split(root,x-1,a,b);
			split(b,1,c,d);
			root=merge(a,d);
		}
		else if ('M'==ch[1]) {
			int x,y;
			scanf("%d%d",&x,&y);
			int a,b,c,d;
			split(root,x-1,a,b);
			split(b,y-x+1,c,d);
			int ans=Min[c];
			root=merge(a,merge(c,d));
			printf("%d\n",ans);
		}
	}
	//cout<<clock()<<endl;
	return 0;
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值