思路分析

自认为是一道很好的思维题。

直接看上去的想法是:

跑一个生成树,每一次加的边颜色交替进行,直到拉出生成树。

仔细想想,发现可能无法保证最后是一棵树而不是森林,也是说输出都是 \(-1\) 。

然后,我这个弱智就没有任何思路了。

这时,想起“拖帝”的名言:正难则反。于是考虑先筛去不合法的情况。(以下的判断以并查集为基础)

  • 当 \(n\) 是偶数时,树边个数是 \(n-1\) 一定是奇数,不可能合法,输出 \(-1\)。
  • 我们不管颜色 \(M\) ,把能加入的 \(S\) 色的边加入生成树,记录选入的 \(S\) 色边的条数 \(cnt_1\) 。当 \(cnt_1 < \frac{n-1}{2}\) 时,一定无解。

    (因为此时所有的 \(S\) 能加入的都加入了,真实情况只少不多,此时都没到一半,就不可能了。)
  • 把 \(M\) 色边能加入的加入生成树,并记录 \(cnt_2\) 。如果 \(cnt_1 + cnt_2 < n-1\) 一定无解。

    (同样 \(M\) 色的边能加的都加上去了,在所需最少的情况下全部加完都不够,不可能有解。)
  • 先还原,然后再扫一遍,类似第二步,把 \(S\) 色改成 \(M\) 色即可。(当 \(cnt_2=\frac{n-1}{2}\) 时有解停止。)

思路就是这样,然后直接把 \(S\) 还原即可。

Code

#include <bits/stdc++.h>

#define file(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)

#define quad putchar(' ')
#define Enter putchar('\n') const int N = 100005; int n, m, fa[N], tot, cnt1, cnt2, visit[N], ans[N];
struct Node {
int x, y, col;
Node (int _x = 0, int _y = 0, int _col = 0) {x = _x; y = _y; col = _col;}
}node[N]; namespace UFS {
inline void init();
inline int find(int x);
} using UFS::find; signed main(void) {
// file("CF141E");
std::cin >> n >> m;
if (n % 2 == 0) {
printf("-1");
return 0;
}
for (int i = 1, x, y; i <= m; i++) {
scanf("%d %d", &x, &y);
char c[4];
scanf("%s", c + 1);
if (c[1] == 'S')
node[++tot] = Node(x, y, 1);
else
node[++tot] = Node(x, y, 2);
}
UFS::init();
for (int i = 1; i <= m; i++) {
int x, y;
if (node[i].col == 2) continue;
x = node[i].x, y = node[i].y;
x = find(x); y = find(y);
if (x == y) continue;
fa[x] = y;
cnt1 ++;
}
if (cnt1 < (n - 1) / 2) {
printf("-1");
return 0;
}
for (int i = 1; i <= m; i++) {
int x, y;
if (node[i].col == 1) continue;
x = node[i].x, y = node[i].y;
x = find(x); y = find(y);
if (x == y) continue;
fa[x] = y; visit[i] = 1;
cnt2 ++;
ans[i] = 1;
}
if (cnt1 + cnt2 < n - 1) {
printf("-1");
return 0;
}
UFS::init();
for (int i = 1; i <= m; i++) {
int x, y;
if (node[i].col == 1) continue;
if (visit[i] == 0) continue;
x = node[i].x, y = node[i].y;
x = find(x); y = find(y);
if (x == y) continue;
fa[x] = y;
}
for (int i = 1; i <= m; i++) {
int x, y;
if (node[i].col == 1) continue;
if (visit[i] == 1) continue;
x = node[i].x, y = node[i].y;
x = find(x); y = find(y);
if (x == y) continue;
fa[x] = y;
cnt2++;
ans[i] = 1;
if (cnt2 == (n - 1) / 2) break;
}
if (cnt2 < (n - 1) / 2) {
printf("-1");
return 0;
}
for (int i = 1; i <= m; i++) {
int x, y;
if (node[i].col == 2) continue;
x = node[i].x, y = node[i].y;
x = find(x); y = find(y);
if (x == y) continue;
fa[x] = y;
ans[i] = 1;
}
printf("%d\n", n - 1);
for (int i = 1; i <= m; i++)
if (ans[i]) printf("%d ", i);
} namespace UFS {
inline void init() {
for (int i = 1; i <= n; i++)
fa[i] = i;
} inline int find(int x) {
if (x == fa[x]) return x;
return fa[x] = find(fa[x]);
}
}

最新文章

  1. TODO:一不顺眼就换字体Go之应用篇
  2. sharepoint关键位置
  3. apache2.4 windows764 python cgi
  4. 通过跳板机建立信任,对多个tomcat服务统一安装部署(shell编写)
  5. 【BZOJ 3672】【UOJ #7】【NOI 2014】购票
  6. 3.3.1实现Servlet
  7. linus用的是哪个桌面?
  8. Schema-based AOP support
  9. linux 下手动编译安装无线网卡驱动
  10. mysql浅龟定
  11. HNOI2017 单旋
  12. Roman to Integer(将罗马数字转成整数)
  13. pycharm的list中append的应用
  14. Java 控制语句
  15. [转]AJAX POST请求中参数以form data和request payload形式在servlet中的获取方式
  16. centos 7 mysql启动失败--学会看错误日志
  17. 第三节《Git重置》
  18. ghostscript远程代码执行漏洞复现
  19. 性能测试二十四:环境部署之Redis多实例部署
  20. 针对appium的webdriver执行swipe无效的解决办法

热门文章

  1. asp.net core MVC 添加静态文件
  2. [源码解析] TensorFlow 分布式之 MirroredStrategy 分发计算
  3. javaScript中Number数字类型方法入门
  4. 电脑UEFI启动是什么?
  5. Blazor和Vue对比学习(基础1.3):属性和父子传值
  6. C# Thread.Sleep 不精准的问题以及解决方案
  7. 使用Go实现健壮的内存型缓存
  8. python面向对象双下划线方法与元类
  9. 一分钟学会如何自定义小程序轮播图(蜜雪冰城Demo)
  10. SpringCloud 服务治理