【Luogu P6922】[ICPC2016 WF]Longest Rivers(贪心)

这篇博客探讨了泰国的主要河流系统—— Chaophraya River System,详细介绍了其最长的六条河流及其长度。文章引入了一个简化模型,并讨论了在不同命名方案下河流排名的变化。博主提出了一种贪心算法来解决如何确定每条河流在所有可能的命名方案中能获得的最小排名。算法基于树形结构,通过小根堆进行优化,以求得每个河流的最优排名。博客还提供了输入输出样例和代码实现,展示了算法的时间复杂度和效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

题目描述

原题传送门
在这里插入图片描述
The Chao Phraya River System is the main river system of Thailand. Its six longest rivers listed by decreasing length are:

Tha Chin ( 765 765 765 km)

Nan ( 740 740 740 km)

Yom ( 700 700 700 km)

Ping ( 658 658 658 km)

Pa Sak ( 513 513 513 km)

Wang ( 335 335 335 km)

A simplified model of this river system is shown in Figure 1, where the smaller red numbers indicate the lengths of various sections of each river. The point where two or more rivers meet as they flow downstream is called a confluence. Confluences are labeled with the larger black numbers. In this model, each river either ends at a confluence or flows into the sea, which is labeled with the special confluence number 0 0 0. When two or more rivers meet at a confluence (other than confluence 0 0 0), the resulting merged river takes the name of one of those rivers. For example, the Ping and the Wang meet at confluence 1 1 1 with the resulting merged river retaining the name Ping. With this naming, the Ping has length 658 658 658 km while the Wang is only 335 335 335 km. If instead the merged river had been named Wang, then the length of the Wang would be 688 688 688 km while the length of the Ping would be only 305 305 305 km.

Figure 1: The river system in Sample Input 1. Same-colored edges indicate a river.

The raised awareness of this phenomenon causes bitter rivalries among the towns along the rivers. For example, the townspeople along the Wang protest that maybe with a proper naming scheme, their river could actually be the longest, or maybe the second longest (or at least not last!). To end all the guessing, your task is to validate all such claims.

The rank of a river is its position in a list of all rivers ordered by decreasing length, where the best rank is 1 1 1 for the longest river. For each river, determine its best possible rank over all naming schemes. At any confluence, the name of a new, larger river in any naming scheme must be one of the names of the smaller rivers which join at that confluence. If two or more rivers have equal lengths in a naming scheme, all the tied rivers are considered to have the best possible ranking. For example, if one river is the longest and all other rivers are equal, those rivers all have rank 2 2 2.

输入格式
The first line of input contains two integers n n n ( 1 ≤ n ≤ 500   000 ) (1 \le n \le 500\, 000) (1n500000), which is the number of river sources in the system, and m m m ( 0 ≤ m ≤ n − 1 ) (0 \le m \le n - 1) (0mn1), which is the number of confluences with positive labels. These confluences are numbered from 1 1 1 to m m m.

The next n n n lines describe the rivers. Each of these lines consists of a string, which is the name of the river at the source, and two integers c c c ( 0 ≤ c ≤ m ) (0 \leq c \leq m) (0cm) and d d d ( 1 ≤ d ≤ 1 0 9 ) (1 \leq d \leq 10^9) (1d109), where c c c is the identifier of the nearest confluence downstream, and d d d is the distance from the source to that confluence in kilometers. River names use only lowercase and uppercase letters a–z, and consist of between 1 1 1 and 10 10 10 characters, inclusive.

The final m m m lines describe confluences 1 1 1 to m m m in a similar fashion. The k th k^\text {th} kth of these lines describes the confluence with identifier k k k and contains two integers: the identifier of the nearest confluence downstream and the distance from confluence k k k to this confluence in kilometers.

It is guaranteed that each confluence 1 1 1 through mm appears as “the nearest downstream” at least twice, confluence 0 0 0 appears at least once, and all sources are connected to confluence 0 0 0.

输出格式
Display one river per line in the same order as in the input. On that line, display the name of the river and its best possible rank.

题意翻译

n n n 条河和 m + 1 m+1 m+1 个交汇处构成一棵以 0 0 0 号点(即大海) 为根的树。

每条河有各自的名称。对于一个交汇处,从它流出的干流的名称是流入这个交汇处的各个支流的名称之一。一条河流的长度是以它为名称的河流的长度之和。对于一个可能的命名方案,一条河流的排名等于长度大于它的河流数 + 1 +1 +1

对于每条河,求出它在所有命名方案中,最小的排名。

输入输出样例

输入 #1
6 2
PaSak 0 513
Nan 2 675
Yom 2 700
Wang 1 335
Ping 1 305
ThaChin 0 765
0 353
0 65
输出 #1
PaSak 5
Nan 2
Yom 1
Wang 3
Ping 4
ThaChin 1

说明/提示

Time limit: 9000 ms, Memory limit: 1048576 kB.

International Collegiate Programming Contest (ACM-ICPC) World Finals 2016

思路

对于一条河流 p p p,如果想是它排名尽可能靠前,河流 p p p 首先要流到根,设它的长度为 L L L
那么,现在我们要使尽可能少的河流比 L L L 短。
考虑其它那些不包括 p p p 的汇流点,有以下 2 2 2 种情况:

  1. 所有流入当前汇流点的河流都比 L L L 短,那么选取最短的河流,让它继续流。
  2. 其中至少有一条流入汇流点的河流比 L L L 长,那么让它继续留。

感性理解一下,这种贪心显然是对的。
可是,对于每一条河流 p p p,都需要进行一遍贪心,时间复杂度为 O ( n 2 ) O(n^2) O(n2),无法通过此题。


那么,我们考虑枚举长度 L L L,考虑对于每一个 L L L,至少会形成多少河流比 L L L 长。
对于每一个节点,都会是以下三种情况:

  1. 至少有一条比 L L L 长的河流流进该节点。
  2. 所有流进的都是比 L L L 短的河流,但流出去的河流一定会变成比 L L L 长的河流。
  3. 所有流进的都是比 L L L 短的河流,且流出后也能比 L L L 短。

L = 0 L=0 L=0 时,所有叶子节点都是状态 2 2 2,其余节点都是状态 1 1 1
随着 L L L 的增长,状态 2 2 2 可能变成状态 3 3 3,状态 1 1 1 可能变成状态 2 / 3 2/3 2/3
我们建立一个小根堆,里面存每一个状态为 2 2 2 的节点。
每个节点有两个值: x x x l l l x x x 表示编号; l l l 表示流出该节点后的长度的最小值,也就是把当前这个状态为 2 2 2 的河流变成状态 3 3 3 的最小长度。
那么,按 l l l 排序,每次取出堆顶的 ( x , l ) (x,l) (x,l),将 L L L 增加到 l l l,把 x x x 的状态改成 3 3 3,然后检查 x x x 的祖先,如果它所有的孩子的状态都为 3 3 3 了,那么就它就可以从原本的状态 1 1 1 变成状态 2 2 2,甚至变成状态 3 3 3
对于每一个 L L L,记录当前状态 2 2 2 的节点个数 + 1 +1 +1,即为长度为 L L L 时的答案。
那么,对于每一条河流 p p p,记其到根长度为 s u m sum sum,那么只需要找到 s u m ≤ L sum \le L sumL 的那个 L L L(二分实现),输出答案即可。
时间复杂度: L L L 不是按顺序增长的,所以总时间复杂度为 O ( n    l o g    n ) O(n\; log \; n) O(nlogn)

代码

#include <bits/stdc++.h>
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
#define mem(a, x) memset(a, x, sizeof a)
#define pb push_back
#define umap unordered_map
#define pqueue priority_queue
#define PI acos(-1)
#define int long long

using namespace std;
typedef long long ll;
int n, m, dp[1000010], fa[1000010], cnt[1000010], W[1000010], S[1000010], A[1000010];
umap <int, int> ans;
string name[1000010];
struct node {
	int y, w;
}; vector <node> e[1000010];
struct Q {
	int l, x;
	bool operator < (const Q &b) const {
		return l > b.l;
	}
}; pqueue <Q> q;

template <typename _T>
void rd(_T &x) {
    int f = 1; x = 0;
    char s = getchar();
    while (s > '9' || s < '0') {if (s == '-') f = -1; s = getchar();}
    while (s >= '0' && s <= '9') x = (x<<3)+(x<<1)+(s-'0'), s = getchar();
    x *= f;
}

void dfs(int x, int F) {
//	printf("%d %d\n", x, F);
	fa[x] = F;
	S[x] = S[F]+W[x];
	int minn = 9e18;
	for (auto i : e[x]) {
		int y = i.y, w = i.w;
		dfs(y, x);
		cnt[x]++;
		minn = min(minn, dp[y]);
	}
	if (minn == 9e18) dp[x] = W[x];
	else dp[x] = minn + W[x];
	return ;
}

signed main() {
	rd(n), rd(m);
	rep(i, m+1, m+n) {
		cin >> name[i];
		int y; rd(y), rd(W[i]);
		e[y].pb((node){i, W[i]});
	}
	rep(i, 1, m) {
		int y; rd(y), rd(W[i]);
		e[y].pb((node){i, W[i]});
	}
	dfs(0, 0);
	int L = 0, s2 = 0;
	rep(i, m+1, m+n) s2++, q.push((Q){dp[i], i});
	int tot = 0;
	while (!q.empty()) {
		Q t = q.top();
		q.pop();
		L = t.l;
		s2--, cnt[fa[t.x]]--;
		if (cnt[fa[t.x]] == 0 && fa[t.x] != 0) {
			int x = fa[t.x];
			while (x != 0 && L >= dp[x]) {
				cnt[fa[x]]--;
				if (cnt[fa[x]] == 0) x = fa[x];
				else break;
			}
			if (x != 0 && cnt[x] == 0 && L < dp[x]) s2++, q.push((Q){dp[x], x});
		}
		ans[L] = s2;
		A[++tot] = L;
	}
	rep(i, m+1, m+n) {
		int id = upper_bound(A+1, A+1+tot, S[i])-A-1;
		cout << name[i] << " ";
		printf("%lld\n", ans[A[id]]+1);
	}
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值