D - Unique Path
题意
已知有一个图有n
个点m
条边
已知q
条线索,以u,v,x
的格式给出
若,表示u,v
之间仅存在一条路径
否则,表示u,v
之间存在多条路经
问,该图是否存在
思路
考虑计算出若该图存在,所需的最少边数和最多边数
-
可以先将所有
0
线索连起来(并查集) -
显然,我们得到多个连通块,且每一个都是树
-
而树和树之间是可以相连的,但只可以连一条线(因为他们之间没有
0
关系) -
考虑
1
线索,他需要将孤立点和连通块串在一个环上 -
最少的情况:从连通块和孤立点组成环,且至少有三个点(整个图要连通)
-
最多的情况:将连通块和孤立点,全部构成完全图
代码
typedef pair<int, int> pii;
const int maxn = 1e5 + 5;
vector<pii> opt[2];
int f[maxn]; //链的并查集
bool vis[maxn];
int find(int x)
{
return x == f[x] ? x : f[x] = find(f[x]);
}
set<int> Set;
int main()
{
long long nn, mm;
scanf("%lld%lld", &nn, &mm);
int q;
scanf("%d", &q);
int u, v, x;
for (int i = 1; i <= q; i++) {
scanf("%d%d%d", &u, &v, &x);
opt[x].push_back(make_pair(u, v));
}
if (nn == 2) {
if (opt[0].size() == 1 && q == 1)
printf("Yes\n");
else
printf("No\n");
return 0;
}
for (int i = 0; i < nn; i++)
f[i] = i;
for (auto it : opt[0]) {
vis[it.first] = vis[it.second] = true;
f[find(it.first)] = find(it.second);
}
long long sum = 0, num = 0;
for (int i = 0; i < nn; i++)
if (vis[i]) {
sum++;
if (find(i) == i)
num++;
}
for (auto it : opt[1]) {
if (vis[it.first] && vis[it.second]) {
if (find(it.first) == find(it.second)) {
printf("No\n");
return 0;
}
}
}
long long lone = nn - sum;
long long m1 = 0, m2 = 0;
if (opt[1].size() == 0) {
m1 = sum - num;
m2 = sum - num + (lone + num) * (lone + num - 1) / 2;
} else {
m1 = sum - num + max(3LL, num + lone);
m2 = (num + lone) * (num + lone - 1) / 2 + sum - num;
}
if (mm >= m1 && mm <= m2) {
printf("Yes\n");
} else
printf("No\n");
return 0;
}