@description@

给定一个 N 个点 M 条边的图,每条为黑色或者白色。

现在让你求一个生成树,使得生成树中黑色边数量等于白色边数量。

Input

第一行两个整数 n, m (1 ≤ n ≤ 10^3, 1 ≤ m ≤ 10^5)。

接下来 m 行,每行描述了一条边 x, y,并给定它的颜色 —— S 为白色,M 为黑色。

注意可以有重边自环。

Output

如果无解,输出 -1。

否则,先输出边的数量,再在下一行依次给出每条边的编号(根据输入顺序)。

如果有多解,输出任意一个解。

Examples

Input

3 3

1 2 S

1 3 M

2 3 S

Output

2

2 1

@solution@

考虑黑色边中有一些必要边:即使加入所有的白边,也需要这些必要边才能保证连通。

白色边,类似地也有必要边的定义:加入所有的黑边也需要这些边才能连通。

可以通过并查集 + 先扫描白色边 + 再尝试加入黑色边求出黑色必要边。同理可以求出白色必要边。

不妨考虑一种情况:即所有边都不是必要边。

这种情况下,黑色边可以让整张图保持连通,白色边也可以让整张图保持连通。

那么我只需要任意加入 (n - 1) / 2 条不形成环的白边,一定可以另外选出 (n - 1) / 2 条黑边形成生成树。

至于为什么。将白边连接的连通块缩成一个新点,则新图中黑边依然可以让整张图保持连通,而连通图一定可以求出一个生成树。

实现直接并查集加 (n - 1) / 2 条白边,再尽量多地塞黑边。

假如我把必要边连接的连通块缩成点,此时所有边都不为必要边,则归于上面那一种情况。

注意特殊情况,如 n - 1 为奇数,或整张图根本不连通,或必要边太多等。

@accepted code@

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXN = 100000;
int x[MAXN + 5], y[MAXN + 5];
vector<int>v[2], ans;
bool tag[2][MAXN + 5];
int fa[MAXN + 5], n, m;
int find(int x) {
return fa[x] = (fa[x] == x ? x : find(fa[x]));
}
bool unite(int x, int y) {
int fx = find(x), fy = find(y);
if( fx != fy ) {
fa[fx] = fy;
return true;
}
else return false;
}
int tot[2];
void get(int t) {
for(int i=1;i<=n;i++) fa[i] = i;
for(int i=0;i<v[!t].size();i++)
unite(x[v[!t][i]], y[v[!t][i]]);
for(int i=0;i<v[t].size();i++)
if( unite(x[v[t][i]], y[v[t][i]]) )
ans.push_back(v[t][i]), tot[t]++, tag[t][i] = true;
}
int main() {
scanf("%d%d", &n, &m);
for(int i=1;i<=m;i++) {
scanf("%d%d", &x[i], &y[i]);
char ch = getchar();
while( ch != 'S' && ch != 'M' )
ch = getchar();
if( ch == 'S' ) v[0].push_back(i);
if( ch == 'M' ) v[1].push_back(i);
}
if( (n - 1) & 1 ) {
puts("-1");
return 0;
}
int mid = (n - 1) >> 1;
get(0), get(1);
if( tot[0] > mid || tot[1] > mid ) {
puts("-1");
return 0;
}
for(int i=1;i<=n;i++) fa[i] = i;
for(int i=0;i<ans.size();i++) unite(x[ans[i]], y[ans[i]]);
for(int i=0;i<v[0].size()&&tot[0]<mid;i++)
if( !tag[0][i] && unite(x[v[0][i]], y[v[0][i]]) )
ans.push_back(v[0][i]), tot[0]++, tag[0][i] = true;
for(int i=0;i<v[1].size()&&tot[1]<mid;i++)
if( !tag[1][i] && unite(x[v[1][i]], y[v[1][i]]) )
ans.push_back(v[1][i]), tot[1]++, tag[1][i] = true;
if( tot[0] != mid || tot[1] != mid ) {
puts("-1");
return 0;
}
printf("%d\n", ans.size());
for(int i=0;i<ans.size();i++)
printf("%d ", ans[i]);
}

@details@

定睛一看。嗯?wqs二分?

不对wqs二分只能求最小权和不能求方案。

注意各种无解的情况吧。其他没有什么细节。

如果一句话总结的话,大概就是:任意一个连通块必然有生成树。

@codeforces - 141E@ Clearing Up的更多相关文章

  1. CodeForces 141E: ...(最小生成树)

    [条件转换] 两两之间有且只有一条简单路径<==>树 题意:一个图中有两种边,求一棵生成树,使得这棵树中的两种边数量相等. 思路: 可以证明,当边的权是0或1时,可以生成最小生成树到最大生 ...

  2. python爬虫学习(5) —— 扒一下codeforces题面

    上一次我们拿学校的URP做了个小小的demo.... 其实我们还可以把每个学生的证件照爬下来做成一个证件照校花校草评比 另外也可以写一个物理实验自动选课... 但是出于多种原因,,还是绕开这些敏感话题 ...

  3. 【Codeforces 738D】Sea Battle(贪心)

    http://codeforces.com/contest/738/problem/D Galya is playing one-dimensional Sea Battle on a 1 × n g ...

  4. 【Codeforces 738C】Road to Cinema

    http://codeforces.com/contest/738/problem/C Vasya is currently at a car rental service, and he wants ...

  5. 【Codeforces 738A】Interview with Oleg

    http://codeforces.com/contest/738/problem/A Polycarp has interviewed Oleg and has written the interv ...

  6. CodeForces - 662A Gambling Nim

    http://codeforces.com/problemset/problem/662/A 题目大意: 给定n(n <= 500000)张卡片,每张卡片的两个面都写有数字,每个面都有0.5的概 ...

  7. CodeForces - 274B Zero Tree

    http://codeforces.com/problemset/problem/274/B 题目大意: 给定你一颗树,每个点上有权值. 现在你每次取出这颗树的一颗子树(即点集和边集均是原图的子集的连 ...

  8. CodeForces - 261B Maxim and Restaurant

    http://codeforces.com/problemset/problem/261/B 题目大意:给定n个数a1-an(n<=50,ai<=50),随机打乱后,记Si=a1+a2+a ...

  9. CodeForces - 696B Puzzles

    http://codeforces.com/problemset/problem/696/B 题目大意: 这是一颗有n个点的树,你从根开始游走,每当你第一次到达一个点时,把这个点的权记为(你已经到过不 ...

随机推荐

  1. web服务器--nginx简介

    nginx 介绍Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务.Nginx是一款轻量级的Web 服务器/反向代理服务器及电 ...

  2. 读书笔记--Head First PMP目录

    1.引言 2.阻止.约束和项目 3.过程框架 4.项目整合管理 5.范围管理 6.时间管理 7.成本管理 8.质量管理 9.人力资源管理 10.沟通管理 11.项目风险管理 12.采购管理 13.职业 ...

  3. webstorm之Monokai-Sublime主题颜色设置方法及激活注册码

    打开https://github.com/OtaK/jetbrains-monokai-sublime 链接,然后点击右边的下载ZIP文件即可.解压之后,会得到一个Monokai-Sublime.ja ...

  4. idea目录结构子目录在父目录后面跟着改成树形结构

    1.点击项目窗口的设置按钮 2.取消Compact Middle Packages选项的对勾即可

  5. Ubuntu 服务器默认的root账号是没有激活的,需要用初装的用户账号给root设置管理密码

    user@ubuntu12:~$ sudo password root //用sudo修改账户 1.根据提示输入当前用户的密码: 2.修改成功之后你就可以使用root账号了,可以使用su root 命 ...

  6. 洛谷P1569属牛的抗议 超级强力无敌弱化版

    P1569 [USACO11FEB]属牛的抗议Generic Cow Prote- 题目描述 约翰家的N头奶牛聚集在一起,排成一列,正在进行一项抗议活动.第i头奶牛的理智度 为Ai,Ai可能是负数.约 ...

  7. python中在计算机视觉中的库及基础用法

    基于python脚本语开发的数字图像处理包有很多,常见的比如PIL.Pillow.opencv.scikit-image等.PIL和pillow只提供了基础的数字图像处理,功能有限:OpenCV实际上 ...

  8. SQLServer2005 没有日志文件(*.ldf) 只有数据文件(*.mdf) 恢复数据库的方法

    代码如下: exec sp_attach_db exun,'d:\exun2.mdf' (可能执行一次不能成功,测试了下,有时候需要执行2次以上命令才行) 执行了之后,记得刷新数据库,不然是不会显示的

  9. Tiles Framework

    tiles framework 详解tiles framework 详解 就是一个页面模版引擎.可以渲染页面,属于视图层. 下面给你拷贝一份详细的tiles介绍,你可以初步了解一下. Tiles框架特 ...

  10. listView中的button控件获取索引

    1.在listitem中初始化button的时候,给该button添加一个setTag方法,将此时的索引值传进去,然后在button的onclick事件中调用view的getTag方法,即可将list ...