PAT 1046 Shortest Distance 树状数组

题意:给定一环路中两两相邻结点之间的距离,随机访问任意两个结点之间的距离。
题解:因为访问的次数过多(10000),并且访问的本质就是区间和,所以考虑用树状数组。原数组中每个下标 i 表示他与前一个结点的距离(i 和 i-1),下标为1表示 的是 1 和N 的距离(1和N之间有一条通路)。所以当我们用树状数组(treearr)重构上述数组之后,就可以通过treearr[i] - treearr[j]得到两点间的一种距离,因为是环路,所以还有另一种走法,另一种走法长度为环路总长减去第一种,这样就可以达到O(nlogn)的时间复杂度了。最后比较两种走法长度,取较小的那个。
代码:

#include<iostream>
#include<stdio.h>
//#define scanf scanf_s
using namespace std;

const int maxn = 1e5 + 7;
int treearr[maxn] = {0};
int answers[10004];
int anssize = 0;
int N;

int lowbit(int x)
{
	return x & -x;
}

void addval(int pos,int v)
{
	for (; pos <= N; pos += lowbit(pos))
	{
		treearr[pos] += v;
	}
}

int ask_interval(int pos)
{
	int sum = 0;
	for (; pos > 0; pos -= lowbit(pos))
	{
		sum += treearr[pos];
	}
	return sum;
}

int main()
{
	
	scanf("%d", &N);
	int tmp;
	for (int i = 0; i < N-1; i++)  //1到N-1
	{
		scanf("%d", &tmp);
		addval(i + 2, tmp);
	}
	scanf("%d", &tmp);   //N与1的距离
	addval(1, tmp);
	int distN = ask_interval(N);
	int M,city1,city2,dist1,dist2;
	scanf("%d", &M);
	for (int i = 0; i < M; i++)
	{
		scanf("%d %d", &city1,&city2);
		if (city1 > city2)
			swap(city1, city2);
		int a = ask_interval(city1);
		int b = ask_interval(city2);
		dist1 = b - a;
		dist2 = distN - b + a;
		answers[anssize++] = dist1 < dist2 ? dist1 : dist2;
	}
	for (int i = 0; i < anssize; i++)
	{
		printf("%d\n", answers[i]);
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值