B. 删边(cip.cpp/in/out 1S/256M)

题面

给出一个没有重边和自环的无向图,现在要求删除其中两条边,使得图仍然保持连通。

你的任务是计算有多少组不合法的选边方案。注意方案是无序二元组。

输入格式

第一行是两个整数 N 和 M,分别表示顶点数和边数

接下来 M 行,每行 2 个整数,表示一条无向边

输出格式

输出一行,表示对应的答案

输入样例

5 6

1 2

2 3

1 3

3 4

4 5

3 5

输出样例

6

数据规模

测试点 N M

10% 3000 7000

70% 50000 100000

100% 100000 300000

题解

首先,如果一条边是桥,那么另一条边任意;

对于非桥边:

构建DFS树。

显然,只有两种组合:树边+树边,树边+返祖边。

对每一条树边记录跨过它的返祖边集合 \(S\) ,返祖边跨过它的集合仅有它本身。

我们就会发现,任意两条非桥边同时删去可以使图不连通的充要条件是跨过他们的返祖边集合相同。

证明显然。

然后考虑如何表示一条边的返祖边集合:

利用哈希,给每条返祖边一个随机权值,加入哈希集合。

把边权变为点权。因为每条边有两个端点,考虑异或,给边的两个端点赋上这条边的权值。

树形dp,每个点异或它的所有儿子的权值,这样某条返祖边未覆盖的点就不会受到它的影响。将每个点的权值加入hash集合,表示这个点到它父亲的边。

哈希值有两种情况:

  1. hash==0 此时这条边为桥,ans+=边数
  2. hash!=0 求出每种哈希值的出现次数 \(m\) ,ans+=m*(m-1)/2

\(ans\) 即为答案。

ps1: 这样似乎可以推广到割k条边?

ps2: tarjan可以省了?

代码

放一下std:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#include<set>
#define SF scanf
#define PF printf
#define mp make_pair
#define fir first
#define sec second
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 100000;
const int MAXM = 300000;
struct Node {
int v, next;
} Edge[MAXM*2+10];
int adj[MAXN+10], ecnt, n, m;
LL Hash[MAXN+10], ans;
bool vis[MAXN+10];
vector <pii> not_tree_edges;
vector <LL> Hash_set;
void addedge(int u, int v) {
Node &e = Edge[++ecnt];
e.v = v; e.next = adj[u]; adj[u] = ecnt;
}
void add(int u, int v) {
addedge(u, v); addedge(v, u);
}
void dfs(int u, int fa) {
vis[u] = true;
for(int i = adj[u]; i; i = Edge[i].next) {
int v = Edge[i].v;
if(!vis[v]) dfs(v, u);
else if(v != fa && v < u) not_tree_edges.push_back(make_pair(v, u));
}
}
LL Rand() {
LL x = 0;
for(int i = 0; i < 3; i++)
x = (x << 16) | rand();
return x;
}
void make_Hash() {
for(int i = 0; i < not_tree_edges.size(); i++) {
LL sta = Rand();
Hash[not_tree_edges[i].fir] ^= sta;
Hash[not_tree_edges[i].sec] ^= sta;
Hash_set.push_back(sta);
}
}
LL calc(int u) {
vis[u] = true;
for(int i = adj[u]; i; i = Edge[i].next) {
if(vis[Edge[i].v]) continue;
LL val = calc(Edge[i].v);
Hash[u] ^= val;
Hash_set.push_back(val);
}
return Hash[u];
}
void count_ans() {
sort(Hash_set.begin(), Hash_set.end());
int cnt = 0;
for(int i = 0; i < Hash_set.size(); i++)
if(!Hash_set[i])
cnt++;
ans += 1LL * cnt * (m - cnt);
for(int i = 0, j = 0; i < m; i = j) {
while(j < m && Hash_set[i] == Hash_set[j]) j++;
int del = j - i;
ans += 1LL * del * (del - 1) / 2;
}
}
int main() {
srand(19981103);
SF("%d%d", &n, &m);
for(int i = 1; i <= m; i++) {
int u, v;
SF("%d%d", &u, &v);
add(u, v);
}
dfs(1, 0);
memset(vis, 0, sizeof(vis));
make_Hash();
calc(1);
count_ans();
cout << ans;
}

[西安交大附中集训] d6 删边(cip)的更多相关文章

  1. [补档]暑假集训D6总结

    考试 不是爆零,胜似爆零= = 三道题,就拿了20分,根本没法玩好吧= = 本来以为打了道正解,打了道暴力,加上个特判分,应该不会死的太惨,然而--为啥我只有特判分啊- - 真的是惨. 讲完题觉得题是 ...

  2. [模板] 数位dp

    数位dp 简介 数位dp指满足特定性质的数的计数, 如求 \([l, r]\) 区间内不含 \(2\) 的数的个数. 一般来说, 数位dp利用dfs解决, 有时状态数较多, 需要hash表优化. 模板 ...

  3. [学习笔记]FWT——快速沃尔什变换

    解决涉及子集配凑的卷积问题 一.介绍 1.基本用法 FWT快速沃尔什变换学习笔记 就是解决一类问题: $f[k]=\sum_{i\oplus j=k}a[i]*b[j]$ 基本思想和FFT类似. 首先 ...

  4. 再探容斥好题——ROOK

    这个时候考过:安师大附中集训 Day2 当时看shadowice1984的做法,但是没有亲自写,,, 雅礼集训考试的时候鼓捣半天,被卡常到80pts,要跑9s 卡不动. 正解实际是: 3重容斥 1.随 ...

  5. TMOOC-1692-分西瓜

    题目 描述 今天是阴历七月初五,首师大附中信息社团队员GDC的生日.GDC正在和SCX.WXY在首师大附中集训.他想给这两位兄弟买点什么庆祝生日,经过调查,GDC发现SCX和WXY都很喜欢吃西瓜,而且 ...

  6. 删边(cip)

    删边(cip) 给出一个没有重边和自环的无向图,现在要求删除其中两条边,使得图仍然保持连通. 你的任务是计算有多少组不合法的选边方案.注意方案是无序二元组. Sol 神题,无从下手啊. 考虑点dfs建 ...

  7. [UOJ#268]. 【清华集训2016】数据交互[动态dp+可删堆维护最长链]

    题意 给出 \(n\) 个点的树,每个时刻可能出现一条路径 \(A_i\) 或者之前出现的某条路径 \(A_i\) 消失,每条路径有一个权值,求出在每个时刻过后能够找到的权值最大的路径(指所有和该路径 ...

  8. 2017/10 冲刺NOIP集训记录:暁の水平线に胜利を刻むのです!

    前几次集训都没有记录每天的点滴……感觉缺失了很多反思的机会. 这次就从今天开始吧!不能懈怠,稳步前进! 2017/10/1 今天上午进行了集训的第一次考试…… 但是这次考试似乎是近几次我考得最渣的一次 ...

  9. 2015UESTC 暑假集训总结

    day1: 考微观经济学去了…… day2: 一开始就看了看一道题目最短的B题,拍了半小时交了上去wa了 感觉自己一定是自己想错了,于是去拍大家都过的A题,十分钟拍完交上去就A了 然后B题写了一发暴力 ...

随机推荐

  1. UVA12253 简单加密法 Simple Encryption

    这题到现在还是只有我一个人过?太冷门了吧,毕竟你谷上很少有人会去做往年ACM比赛的题 题面意思很简单,每次给出\(K_1\),让你求一个\(K_2\)满足\(K_1^{K_2}\equiv K_2(\ ...

  2. 蓝牙speaker配对流程源码分析

    这篇文章简单分析一下 蓝牙音箱配对流程.现在的音箱基本都支持security simple pairing.所以这里的流程基本上就是ssp的代码流程. 源码参考的是 Android 6.0 上面的bl ...

  3. JVM参数配置 java内存区域

    java内存区域 一些基本概念 http://www.importnew.com/18694.html https://www.cnblogs.com/wangyayun/p/6557851.html ...

  4. Linux:一位猫奴的意外逆袭

    作者:Vamei,严禁任何形式转载. 1991年年中,林纳斯·托瓦兹(Linus Torvalds)在自己房间里敲着键盘.他全神贯注地盯着14寸的黑色屏幕,都没感觉到自己的小猫Randi在扒自己的裤腿 ...

  5. Flask发送邮件

    参考:官方文档:https://pythonhosted.org/Flask-Mail/ 1.安装插件  Flask-Mail (pip install Flask-Mail) 2.配置 Flask- ...

  6. NODE 模块 FS-EXTRA

    fs-extra模块是系统fs模块的扩展,提供了更多便利的 API,并继承了fs模块的 API. 1.复制文件 copy(src, dest, [options], callback) 示例: var ...

  7. python-BeautifulSoup库详解

    快速使用 通过下面的一个例子,对bs4有个简单的了解,以及看一下它的强大之处: from bs4 import BeautifulSoup html = ''' <html><hea ...

  8. p2394 精度题

    题意:输出n/23即可 解法一: 利用高精度的long double直接输出,但由于n的长度不确定,我们要加个限制%12Lf #include <cstdio> int main(){ l ...

  9. c++入门之结构体初步

    结构体实际上是一种数据结构的雏形,对结构体的灵活使用很多时候可以带来很多便利.下面给出一个关于结构体的程序: #include "iostream" # include " ...

  10. net core 端口设置

    在supervisor的启动配置里面增加环境变量: environment=ASPNETCORE_URLS='http://*:5001'