2012 noip 开车旅行(倍增)

对于每个点要找离它次近和最近的点,我们可以先把海拔高度排序,对于点i , 离他次近和最近的点一定在i-1,i-2,i+1,i+2这四个位置中,先找最近再找次近=、=

因为一直往右走,所以按排序前每个点的位置从左往右找,找完一个点删除,这样可以保证次近点和最近点都在该点的右边,同时可以保证信息的连续性。

sta[i][j]表示a在i这个点开车,过2^j轮后,a走的路程;stb同理

f[i][j]表示车在i这个点,过2^j轮(一轮为a先开一次车,b再开一次车)后,所到达的点;

我们可以用倍增处理出来;

然后可以通过sta[i][j],stb[i][j],f[i][j]求出出a到某点走的路程,和b某点走的路程

然后对于询问一,枚举每个点,找比值最小。

对于询问二,直接输出所求的距离就好

#include
#include
#include
using namespace std;
struct node
{
   int v,num,l,r;	
};
node q[100005];
int la, lb, n, m, ans, f[100005][21],p[100005],zj[100005],cj[100005];
long long sta[100005][21],stb[100005][21];
double mi = 1e30;
bool cmp(node const a,node const b)
{
	return a.v <  b.v;
}
bool zuo(int x)
{
	if(q[x].r == 0) return 1;
    if(q[x].l == 0) return 0;
    return (q[x].v - q[q[x].l].v <= q[q[x].r].v - q[x].v)? 1 : 0;
}
int pd(int j,int x,int  y)
{
	if(x == 0) return q[y].num;
	if(y == 0) return q[x].num;
	if(q[j].v - q[y].v <=q[x].v - q[j].v) return q[y].num;
	return q[x].num;
}
void init()
{
	for(int i = 1; i <= 19; i++)
	for(int j = 1; j <= n; j++)
	{
		f[j][i] = f[f[j][i-1]][i-1];
		sta[j][i] = sta[j][i-1] + sta[f[j][i-1]][i-1];
		stb[j][i] = stb[j][i-1] + stb[f[j][i-1]][i-1];
	}
}
void getjl(int qd,int jl)
{
	long long  lc = 0;
	for(int i = 19 ; i >= 0; i--)
	{
		if(f[qd][i] &&(long long)( sta[qd][i] + stb[qd][i] + lc) <= jl)
		{  
		    la += sta[qd][i];
		    lb += stb[qd][i];
			lc = lc + sta[qd][i] + stb[qd][i];
			qd = f[qd][i];
		}
	}
	if(cj[qd] && lc + sta[qd][0] <= jl)
	{
		la += sta[qd][0];
	}
}
int main()
{
	cin >> n;
	for(int i = 1; i <= n; i++)
	{
		scanf("%d",&q[i].v);
	      q[i].num = i;
	}
	sort(1+q,1+q+n,cmp);
	for(int i = 1; i <= n;i++) p[q[i].num] = i;
	for(int i = 1; i <= n; i++)
	{
		q[i].l = i - 1;
		q[i].r = i + 1;
	}
	q[1].l = 0; q[n].r = 0;
	for(int i = 1; i <= n; i++)
	{
		int j = p[i];
		if(zuo(j)){zj[i] = q[q[j].l].num;cj[i] = pd(j,q[j].r,q[q[j].l].l);}
		else  {zj[i] = q[q[j].r].num;cj[i] = pd(j,q[q[j].r].r,q[j].l);}
		if(q[j].l != 0) q[q[j].l].r = q[j].r;
		if(q[j].r != 0) q[q[j].r].l = q[j].l;
	}
	for(int i = 1; i <= n; i++)
	{
		f[i][0] = zj[cj[i]];
		sta[i][0] = abs(q[p[cj[i]]].v - q[p[i]].v);
		stb[i][0] = abs(q[p[cj[i]]].v - q[p[f[i][0]]].v);
	}
    init();
    int x0;
	cin >> x0;
	for(int i = 1; i <= n; i++)
	{
		la = 0;
		lb = 0;
		getjl(i,x0);
		if(lb != 0 && (1.0* la/lb ) < mi)
		{
			mi = (1.0* la/lb );
			ans = i;
		}
	}
	cout << ans << endl;
	cin >> m;
	for(int i = 1 ;i <= m; i++)
	{
		la = 0;
		lb = 0;
		int qd,lc;
		scanf("%d%d", &qd, &lc);
		getjl(qd,lc);
		cout << la << " " << lb << endl;
	}
	return 0;
}

 

你可能感兴趣的:(倍增,noip训练)