折磨
在一个无向社交网络中,已知每名用户的心动价位及初始发出“瓜条”的源头节点(当用户看到不低于自身心动价位的瓜条时会转发并更新心动价位,引发扩散),计算为使指定节点(猫猫)完全接收不到任何瓜条,最少需要屏蔽猫猫的多少个直接好友。
猫猫的社交网络中有 位用户,他们编号为 ,其中猫猫的编号为 。
每名用户的心中都会有一个心动价位 ,当它看到的瓜条金额 心动价位,该用户就会心动并转发该瓜条,同时它的心动价位也会更新为瓜条金额。
现在有 位用户在同一时刻发出了瓜条,瓜条金额为发出者的初始心动价位,不会再变。每个瓜条一旦发出就会出现在该用户空间里,该用户的所有好友立即可见;好友若心动会转发,转发的瓜条会出现在该好友的空间里,对该好友的所有好友可见,如此层层扩散……
由于这只笨猫没有底线(其心动价位为 ),为了避免自己转发,在他看到任何瓜条前,猫猫决定立刻屏蔽自己的一些好友,猫猫不会查看被自己屏蔽的好友的空间。
那么猫猫至少需要屏蔽多少个好友呢?可以证明看到瓜条的顺序并不会影响最终结果。
输入格式
第一行 个正整数 ,代表着总用户数、好友关系数、发送瓜条的用户数、猫猫的编号。
接下来 行共有 个非负整数,代表着每名用户初始的心动价位 。
接下来 行,每行 个正整数 ,代表着用户 和用户 是好友关系。
接下来 行共有 个正整数,代表着发送瓜条用户的编号,数据保证猫猫自己不会发送瓜条。
输出格式
一个整数,代表着最少需要屏蔽的好友数目。
样例
输入样例 1
6 8 2 30 0 0 0 1 01 31 51 62 52 63 43 55 64 6输出样例 1
2输入样例 2
6 8 1 30 0 0 0 0 01 31 51 62 52 63 43 55 64输出样例 2
1样例 1 的解释
在本组样例中一共涉及到 名用户,有 对好友关系,猫猫的节点编号为 ,关系网络中有 名瓜条发送者:用户 和用户 。
其中猫猫的好友为用户 、用户 、用户 。由于用户 的瓜条金额 达到了用户 的心动价位 ,因此用户 将会转发瓜条,而用户 的心动价位 高于用户 的瓜条金额 ,因此用户 不会转发瓜条。
而用户 既是猫猫的好友,又是瓜条的发送者,它的空间内也有瓜条。
因此,如果猫猫不想看到瓜条,最终至少需要屏蔽 个好友:用户 和用户 。
因此最终答案输出 。
数据范围与约束
本题共有 个测试点,对于第 个测试点,每个测试点通过后可以得到 分;对于第 个测试点,每个测试点通过后可以得到 分。
对于 的数据满足:,,,。
测试点编号 特殊性质 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 无 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 无 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 无 特殊性质 :心动价位最高的用户一定是瓜条发送者,且在没有屏蔽任何用户的条件下,该用户的瓜条最终会被猫猫的每一位好友看见。
特殊性质 :社交网络是一棵树。
特殊性质 :社交网络是菊花图。
特殊性质 :社交网络是一条链。
特殊性质 :社交网络是连通图。
这道题的核心是分析瓜条信息的传播机制,以及猫猫为了不看到任何瓜条,需要切断哪些连向其好友的边。
网络是一个无向图,包含 个节点和 条边。猫猫位于节点 。
对于任何一个瓜条,它的本质是一个带有权值(金额) 的信息,在图上传播:
当金额为 的瓜条传到节点 时:
- 如果 ,节点 会心动并转发(同时其心动价位更新为 ),该瓜条会继续传给 的所有邻居。
- 如果 ,节点 不转发,传播在该节点终止。
关键观察:
如果节点 转发了某个瓜条,其心动价位会提高(更新)为 。后续如果有金额更高()的瓜条到来,由于金额依然大于等于当前已抬高的心动价位,节点 依然会继续转发。而在本题的求解逻辑中,只要猫猫的好友自身是发瓜者,或者至少转发过一次瓜条,猫猫就必须将其屏蔽。
题目只允许猫猫屏蔽自己的好友(即删除节点 与其邻居 之间的边)。
猫猫不能改变其他节点之间的传播逻辑,因此:
- 如果猫猫的某个好友 最终拥有/转发了任何一个瓜条,那么猫猫如果不屏蔽 ,就一定会从 这里看到瓜条。
- 只要确定哪些好友 最终会触发瓜条转发(或本身就是初始发瓜者),猫猫就必须屏蔽这些好友。
因此,最少屏蔽的好友数 = 猫猫的所有好友中,最终能够拥有/转发瓜条的节点个数。
题目保证删去猫猫与好友的边不影响传播本身(因为猫猫自己不会发瓜,且猫猫心动价为 ,屏蔽发生在传播之前,猫猫只作为一个被动接收端)。
我们可以直接在去掉了猫猫节点 的图上(或者原图上不经过 )运行多源最短路/松弛算法:
-
定义状态:
表示到达节点 的瓜条的最大金额(初始全为 )。
如果初始节点 是发瓜者,则其初始拥有金额为 的瓜条,即 。
-
传播机制:
用类似于 Dijkstra 或 SPFA/BFS 的优先队列(按瓜条金额从大到小排序):
- 优先处理当前金额较大的瓜条。当节点 拥有金额为 的瓜条且 时,它会将 传播给所有邻居 。
- 如果 ,更新 ,并将 加入队列。
-
统计答案:
在传播结束后,遍历猫猫的所有好友 :
- 如果 是初始发瓜者,或者 (即 收到过金额 的瓜条),则猫猫必须屏蔽 。
- 统计满足条件的好友数量,即为答案。
#include <iostream>#include <vector>#include <queue>
using namespace std;
const int MAXN = 200005;
struct Node { int u; int w; bool operator<(const Node& other) const { return w < other.w; // 大顶堆,优先传播金额大的瓜条 }};
int N, E, M, A;int a[MAXN];vector<int> adj[MAXN];int max_w[MAXN]; // 记录节点到达的最大瓜条金额bool is_sender[MAXN];
int main() { ios::sync_with_stdio(false); cin.tie(nullptr);
cin >> N >> E >> M >> A; for (int i = 1; i <= N; ++i) { cin >> a[i]; max_w[i] = -1; }
for (int i = 0; i < E; ++i) { int u, v; cin >> u >> v; adj[u].push_back(v); adj[v].push_back(u); }
priority_queue<Node> pq;
for (int i = 0; i < M; ++i) { int sender; cin >> sender; is_sender[sender] = true; max_w[sender] = a[sender]; pq.push({sender, a[sender]}); }
// 传播过程(传播时跳过猫猫节点 A) while (!pq.empty()) { auto [u, w] = pq.top(); pq.pop();
if (w < max_w[u]) continue;
for (int v : adj[u]) { if (v == A) continue; // 猫猫屏蔽了自己,不参与传播过程
// 如果瓜条金额大于等于邻居的心动价,且比邻居收到的已有最大金额更大 if (w >= a[v] && w > max_w[v]) { max_w[v] = w; pq.push({v, w}); } } }
// 统计猫猫需要屏蔽的好友数量 int ans = 0; for (int u : adj[A]) { // 如果好友自身发了瓜,或者收到了能够触发转发的瓜 if (is_sender[u] || max_w[u] >= a[u]) { ans++; } }
cout << ans << "\n";
return 0;}