ABC 158 D(图,fake)

前言

image
(截图于kenkoooo.com
嗯,没错,这是一道青题。所以这是一道E题
不过照样被我自己做出来了。
做出这题算什么,我可是全世界最弱的
链接:$ \sum _ {i = 1} ^ {n} {a}_{i} $

正文

题目大意

Takahashi 有一个 SNS。(下文我们称为WorldBBS)
在 WorldBBS 上,有朋友,也有死对头。
现在,我们的 Takahashi 要增加一个新功能:朋友推荐。
如果 y 要被推荐给 x,则必须满足以下几个要求:

  • y 不是 x 的朋友。(不然还推荐干啥)
  • y 不是 x 的死对头。(推荐了也不会加)
  • y 是 x 的间接朋友。所谓的间接朋友是指 y 是 x 的朋友的朋友的朋友……这里不论是有 2 个“朋友”还是 1000000 个都没关系。
    现在让你求出被推荐给每个人的朋友数。

思路

这题一看就是个图,毕竟我们可以按照友谊和死对头关系建两张图嘛!
对于友谊我们处理出每个连通集,并处理出每个连通集的节点个数。
首先我们把节点个数减 1 后再减朋友的个数,因为朋友推荐总不能推荐原先的朋友(离谱)和自己(更离谱)嘛。
对于那些间接的死对头咋办呢?(比如:1 3 是朋友,3 2 是朋友,1 2 是死对头)
考虑到每个人的死对头加起来才 $ 100000 \times 2 = 200000 $。
我们可以把连通集存进 set 而非 vector 里,然后找到一个就减 1。
Over.

代码

#include <bits/stdc++.h>
using namespace std;

vector<set<int> > comp;
int len;
vector<int> good[100005], bad[100005];
int vis[100005];

void dfs(int x, int flag) {
	if (vis[x]) {
		return;
	}
	vis[x] = flag;
	comp[flag].insert(x);
	for (auto adjacent : good[x]) {
		dfs(adjacent, flag);
	}
}

int main() {
	int n, m, k;
	scanf("%d %d %d", &n, &m, &k);
	for (int i = 0; i < m; i++) {
		int a, b;
		scanf("%d %d", &a, &b);
		a--, b--;
		good[a].push_back(b);
		good[b].push_back(a);
	}
	for (int i = 0; i < k; i++) {
		int c, d;
		scanf("%d %d", &c, &d);
		c--;
		d--;
		bad[c].push_back(d);
		bad[d].push_back(c);
	}
	comp.emplace_back();
	for (int i = 0; i < n; i++) {
		if (!vis[i]) {
			comp.emplace_back();
			dfs(i, ++len);
		}
	}
	for (int i = 0; i < n; i++) {
		int ans = comp[vis[i]].size() - good[i].size();
		for (int blocked : bad[i]) {
			ans -= comp[vis[i]].count(blocked);
		}
		printf("%d ", ans - 1);
	}
	return 0;
}

后续

kenkoooo是个好网站!
它不仅能统计你的AC数,连续AC天数,当然还有那个古怪的TEE(tourist 把你 AC 过的题全刷一遍要多少秒)外,还能统计题目的Rating并给你推荐题目!
比方说这题,我就是在Hard的题目中找到这题的。
但是kenkoooo好像也就这个东东了……


各位神犇们行行好吧
蒟蒻推荐太少了
求大家推荐一下吧
大家都是OIer这个物种啊!!!

posted @ 2022-07-30 22:00  A-Problem-Solver  阅读(43)  评论(0编辑  收藏  举报