洛谷P7043 村国

传送门

Solution:

这题乍一看毫无思路,但是仔细思考(指思考了两天),找到了突破口。

手玩一下样例,设最大值为 A i A_i Ai(在第 i i i个结点),那么在旅行若干次 i i i后,其相邻结点中会有一个 A j = A i A_j = A_i Aj=Ai(在第j个结点)。此时若 i i i < j j j,则继续旅行 i i i,使得 A j = A i + 1 A_j = A_i + 1 Aj=Ai+1。接下来应该旅行 j j j,而旅行一次 j j j后,因为 j j j的相邻结点中 i i i A A A值最大,且此时 A i A_i Ai又会大于(或等于,取决于 i i i j j j的大小关系)又应该旅行 i i i

所以应该先旅游几天,若旅行完 M M M A i > A j A_i > A_j Ai>Aj(由 A A A数组中元素的范围可知,使 A i = A j A_i = A_j Ai=Aj的天数 < 2 31 2^{31} 231),则直接输出 i i i,否则接下来判断 M − ( A i − A j ) M - (A_i - A_j) M(AiAj)的奇偶性。

可以配合代码理解。

code:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

typedef long long LL;
const int MAXN = 4000007;
const int INF = 99999999;
int T, N;
LL M;
int A[MAXN];
struct Edge {
	int u, v, nxt;
	Edge (int u = 0, int v = 0, int nxt = 0) : u(u), v(v), nxt(nxt) {}
}e[MAXN];
int fir[MAXN], tote;
struct Node {
	int id, x;
	bool operator < (const Node h) const {return x == h.x ? id > h.id : x < h.x;} 
	// 重载小于运算符,当x != h.x时比较x,当x == h.x时比较其id值。
	Node (int id = 0, int x = 0) : id(id), x(x) {}
}mxi, mxj;

void Clear() {
	memset(fir, 0, sizeof(fir));
	tote = 0;
	mxi = mxj = Node(INF, 0);
}
void addedge(int x, int y) {
	e[++tote] = Edge(x, y, fir[x]);
	fir[x] = tote;
}
int main() {
	#ifdef test
		freopen("test.txt", "r", stdin);
	#endif
	cin >> T;
	while(T--) {
		cin >> N >> M;
		Clear();
		for(int i = 1; i <= N; i++) {
			scanf("%d", &A[i]);
			Node h = Node(i, A[i]);
			mxi = max(mxi, h);
		}
		if(N == 1) {
			printf("1\n");
			continue;
		}
		int x, y;
		for(int i = 1; i < N; i++) {
			scanf("%d %d", &x, &y);
			addedge(x, y), addedge(y, x);
		}
		
		for(int i = fir[mxi.id]; i; i = e[i].nxt) 
			mxj = max(mxj, Node(e[i].v, A[e[i].v]));
		
		//mxi代表A值最大的节点,mxj代表mxi相邻的节点中A值最大的那个点。
		int h = mxi.x - mxj.x; 
		if(M < h) {cout << mxi.id << endl; continue;} // M不满足二者的差值。
		M -= h;
		mxj.x = mxi.x; 
		if(mxi < mxj) swap(mxi, mxj);
		if(M & 1) cout << mxj.id << endl; // M&1 即 M%2==1
		else cout << mxi.id << endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值