【NOIP2012提高组】开车旅行

这题倍增。
当拿到a数组时,我们便记录他的位置并排个序(再用一个数组)
然后,我们就将其变成一个链表的样子。
由于题目要求每次这能从左边走到右边,
所以我们便从1开始枚举到n,

设nx[i][j]表示从i走2j步所到达的点

f[i][j][0/1]表示到达A/B所走的路程

(一步表示A一天+B一天)

PS:luogu的也A了
上标:

#include<cstdio>
#include<algorithm>
#define ll long long
#define N 100010
using namespace std;
ll nx[N][19],f[N][19][2],cl[N][2];
int n,X,m,a[N],b[N],c[N],l[N],r[N],s,x;
ll A,B,fr=0,mA=(1<<30),mB=1;

inline int read()
{
	int x=0,f=0; char c=getchar();
	while (c<'0' || c>'9') f=(c=='-') ? 1:f,c=getchar();
	while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return f ? -x:x;
}

void qsort(int l,int r)
{
	int i=l,j=r,mid=c[l+r>>1],mid1=b[l+r>>1];
	while (i<j)
	{
		while (c[i]<mid || (c[i]==mid && b[i]<mid1)) i++;
		while (c[j]>mid || (c[j]==mid && b[j]>mid1)) j--;
		if (i<=j)
		{
			swap(c[i],c[j]);
			swap(b[i],b[j]);
			i++,j--;
		}
	}
	if (i<r) qsort(i,r);
	if (l<j) qsort(l,j);
}

void jump(int x,int s)
{
	A=0,B=0;
	for (int i=16;i>=0;i--)
		while (nx[x][i] && A+B+f[x][i][0]+f[x][i][1]<=s)
				A+=f[x][i][0],B+=f[x][i][1],x=nx[x][i];
	if (cl[x][1] && A+B+abs(a[cl[x][1]]-a[x])<=s) A+=abs(a[cl[x][1]]-a[x]);
}

int main()
{
	freopen("drive.in","r",stdin);
	freopen("drive.out","w",stdout);
	n=read();
	for (int i=1;i<=n;i++) c[i]=a[i]=read(),b[i]=i;
	qsort(1,n);
	for (int i=1;i<=n;i++) l[b[i]]=b[i-1],r[b[i]]=b[i+1];
	for (int i=1;i<=n;i++)
	{
		if (!l[i] && !r[i]) continue;
		if (!l[i]) cl[i][0]=r[i],cl[i][1]=r[r[i]],l[r[i]]=0;
		else if (!r[i]) cl[i][0]=l[i],cl[i][1]=l[l[i]],r[l[i]]=0;
		else
		{
			if (abs(a[i]-a[l[i]])==abs(a[i]-a[r[i]]))
			{
				if (a[l[i]]<a[r[i]])
				{
					cl[i][0]=l[i],cl[i][1]=r[i];
					r[l[i]]=r[i],l[r[i]]=l[i];
				}
				else
				{
					cl[i][0]=r[i],cl[i][1]=l[i];
					r[l[i]]=r[i],l[r[i]]=l[i];
				}
			}
			else if (abs(a[i]-a[l[i]])<abs(a[i]-a[r[i]]))
			{
				cl[i][0]=l[i];
				if (!l[l[i]]) cl[i][1]=r[i];
				else if (abs(a[i]-a[l[l[i]]])==abs(a[i]-a[r[i]]) && a[l[l[i]]]<a[r[i]]) cl[i][1]=l[l[i]];
				else if (abs(a[i]-a[l[l[i]]])<abs(a[i]-a[r[i]])) cl[i][1]=l[l[i]];
				else cl[i][1]=r[i];
				r[l[i]]=r[i],l[r[i]]=l[i];
			}
			else
			{
				cl[i][0]=r[i];
				if (!r[r[i]]) cl[i][1]=l[i];
				else if (abs(a[i]-a[r[r[i]]])==abs(a[i]-a[l[i]]) && a[r[r[i]]]<a[l[i]]) cl[i][1]=r[r[i]];
				else if (abs(a[i]-a[r[r[i]]])<abs(a[i]-a[l[i]])) cl[i][1]=r[r[i]];
				else cl[i][1]=l[i];
				r[l[i]]=r[i],l[r[i]]=l[i];
			} 
		}
	}
	for (int i=1;i<=n;i++)
	{
		nx[i][0]=cl[cl[i][1]][0];
		if (cl[i][1])
		{
			f[i][0][0]=abs(a[cl[i][1]]-a[i]);
			if (nx[i][0])
				f[i][0][1]=abs(a[nx[i][0]]-a[cl[i][1]]);
		}
	}
	for (int j=1;j<=16;j++)
		for (int i=1;i<=n;i++)
		{
			nx[i][j]=nx[nx[i][j-1]][j-1];
			f[i][j][0]=f[i][j-1][0]+f[nx[i][j-1]][j-1][0];
			f[i][j][1]=f[i][j-1][1]+f[nx[i][j-1]][j-1][1]; 
		}
	X=read();
	for (int i=1;i<=n;i++)
	{
		jump(i,X);
		if (!B) continue;
		if ((double)mA/mB>(double)A/B)
			mA=A,mB=B,fr=i;
	}
	printf("%d\n",fr);
	m=read();
	for (int i=1;i<=m;i++)
	{
		s=read(),x=read(),jump(s,x);
		printf("%lld %lld\n",A,B);
	}
	return 0;
}
posted @ 2019-01-20 07:42  jz929  阅读(173)  评论(0编辑  收藏  举报