码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj-4172 弹珠

时间:2015-08-12 16:46:21      阅读:288      评论:0      收藏:0      [点我收藏+]

标签:bzoj   splay   斜率优化   

题意:

白板题,略去;


题解:

首先根据操作用Splay维护序列;

注意维护之后的序列应该保证是n个的;

然后就有三个数组a[i],p[i],q[i];

令f[i]表示用前面的弹珠撞击第i个弹珠的最大得分;

那么f[i]=max(0,-a[i]*p[j]+q[j]);

(0<j<i)

暂时不考虑0,变形可得q[j]=a[i]*p[j]+f[i];

这显然是一个斜率优化的形式,维护一个上凸壳,在凸壳上二分就好了;

0的情况就是加一个原点进去咯,反正不会被T出凸壳;

二分不太好写,但是似乎二分完了对l,r的答案取个max就好写多了(笑);

时间复杂度O(mlogn+nlogn);

这题分明是两道题!



代码:


#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 410000
#define which(x)	(ch[fa[x]][1]==x)
using namespace std;
typedef long long ll;
int fa[N],ch[N][2],size[N],root,tot,cnt;
ll val[N],a[N],x[N],y[N];
int n,m,i,st[N],top;
char str[100];
void Pushup(int x)
{
	size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
}
void Rotate(int x)
{
	int f=fa[x];
	bool k=which(x);
	ch[f][k]=ch[x][!k];
	ch[x][!k]=f;
	ch[fa[f]][which(f)]=x;
	fa[ch[f][k]]=f;
	fa[x]=fa[f];
	fa[f]=x;
	size[x]=size[f];
	Pushup(f);
}
void Splay(int x,int g)
{
	while(fa[x]!=g)
	{
		int f=fa[x];
		if(fa[f]==g)
		{
			Rotate(x);
			break;
		}
		if(which(x)^which(f))
			Rotate(x);
		else
			Rotate(f);
		Rotate(x);
	}
	if(!g)	root=x;
}
int rank(int x,int k)
{
	if(k<=size[ch[x][0]])
		return rank(ch[x][0],k);
	else if(k==size[ch[x][0]]+1)
		return x;
	else
		return rank(ch[x][1],k-size[ch[x][0]]-1);
}
void Insert(int k,ll v)
{
	int x=rank(root,k),y=rank(root,k+1);
	Splay(x,0),Splay(y,x);
	fa[++tot]=y;
	size[tot]=1;
	ch[y][0]=tot;
	val[tot]=v;
	Pushup(y);
	Pushup(x);
}
void Change(int k,ll v)
{
	int x=rank(root,k);
	val[x]=v;
	Pushup(x);
}
void Print(int x)
{
	if(!x)	return ;
	Print(ch[x][0]);
	a[++cnt]=val[x];
	Print(ch[x][1]);
}
double slope(int a,int b)
{
	if(b>=i)	return 0;
	return(double(y[a]-y[b]))/(x[a]-x[b]);
}
int main()
{
	int j,k,l,r,mid;
	ll v;
	scanf("%d%d",&n,&m);
	tot=2;
	ch[1][1]=2,fa[2]=1;
	root=1;
	for(i=1;i<=m;i++)
	{
		scanf("%s%d%lld",str,&k,&v);
		if(str[0]=='I')
			Insert(k+1,v);
		else
			Change(k+2,v);
	}
	cnt=-1;
	Print(root);
	for(i=1;i<=n;i++)
		scanf("%lld%lld",x+i,y+i);
	st[top=2]=1;
	for(i=2;i<=n;i++)
	{
		l=1,r=top;
		while(l<=r)
		{
			mid=l+r>>1;
			if(slope(st[mid],st[mid+1])>a[i])
				l=mid+1;
			else
				r=mid-1;
		}
		printf("%lld\n",max(y[st[l]]-a[i]*x[st[l]],y[st[r]]-a[i]*x[st[r]]));
		while(top>1&&(y[st[top]]-y[st[top-1]])*(x[i]-x[st[top]])<=
		(y[i]-y[st[top]])*(x[st[top]]-x[st[top-1]]))
			top--;
		st[++top]=i;
	}
	return 0;
}




bzoj-4172 弹珠

标签:bzoj   splay   斜率优化   

原文地址:http://blog.csdn.net/ww140142/article/details/47446429

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!