[西安交大附中集训] d6 删边(cip)

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;
}

原文地址:https://www.cnblogs.com/ubospica/p/10146135.html

时间: 2024-11-14 13:10:44

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

[模板] 数位dp

数位dp 简介 数位dp指满足特定性质的数的计数, 如求 \([l, r]\) 区间内不含 \(2\) 的数的个数. 一般来说, 数位dp利用dfs解决, 有时状态数较多, 需要hash表优化. 模板: // 求[l,r] 中各位数字之积为特定值(prod[])数的个数 ll dp[nsz][35][25][15][15]; ll dfs(int p,ll v,ll base,ll l,ll r){ ll maxv=v+base-1; if(maxv<l||v>r)return 0; if(p

俱怀逸兴壮思飞,欲上青天览明月

国赛准备期间,我们联系了tywz,和他们的选手一起去湖南师大附中集训,yqszxy欣然答应.其实这个级别的集训就是过去跟他们的选手刷题,主办学校会请一些历年的国家集训队的选手给他们讲题.对于sx这样的弱省来说,几百年也出不了一个金牌选手,所以只能跑到强省去交学费,而强省则靠着自产的金牌选手很快孵化出下一枚.下下一枚金牌,这个良性循环对竞赛学习弥足珍贵. Yqszxy去湖南师大付不到一个月就跑回来了,独自一个人在家看论文刷题.有时经常跑过来找我聊天,我深知这样的抉择过于残忍,因为他是tfls第一人

TMOOC-1692-分西瓜

题目 描述 今天是阴历七月初五,首师大附中信息社团队员GDC的生日.GDC正在和SCX.WXY在首师大附中集训.他想给这两位兄弟买点什么庆祝生日,经过调查,GDC发现SCX和WXY都很喜欢吃西瓜,而且一吃就是一堆的那种,GDC立刻下定决心买了一堆西瓜.当他准备把西瓜送给SCX和WXY的时候,遇到了一个难题,WXY和SCX不在一块住,只能把西瓜分成两堆给他们,为了对每个人都公平,他想让两堆的重量之差最小.每个西瓜的重量已知,你能帮帮他么? 输入 输入多组测试数据(<=1500).数据以EOF结尾,

[北京集训测试赛(五)/HDU5299]圆圈游戏(Circles game)-树上删边-圆的扫描线

Problem 遗产 题目大意 一个平面上n个圆,任两个圆只会相离或包含,给出每个圆位置与半径. alice&&bob轮流取圆,每取一个就可以取出这个圆以及被这个圆包含的圆. 没圆取的人输,alice先取,问谁有必胜策略. Solution Method #1 首先我们考虑一个暴力一点的写法: 先将圆半径从小到大排序,然后枚举两个圆,判断是否包含关系. 如果包含的话就将大圆连一条边到小圆. 很容易发现,这样执行完以后得到了一棵树. 我们接下来要做的事情就变成了: 每个人可以轮流从树上删除一

集训前

今天,参加地大的邀请赛,本来是自己领队_Fffm战队出征的,但是队友略坑,此处就不说了.(话说,ACM想组一个好队,真的得志同道合的人啊).算是_Fffm战队,就正式解散了吧.但是自己在暑假集训期间,一定会把他建起来的,加油. 于是临时的,我和DB队拼成了一个队出战.这也算是自己的首战了,按照自己不爆0的初衷,算是这场比赛也可以无悔了.但是第一题,真的是大水哦.自己做了2个多小时,但是还是没有A掉,这就很大程度的影响了后面的题吧.这算是最大的遗憾吧.(今天跟其中一队友,虽然是首次合作,但是感觉还

bzoj 4736 /uoj274【清华集训2016】温暖会指引我们前行 lct

[清华集训2016]温暖会指引我们前行 统计 描述 提交 自定义测试 寒冬又一次肆虐了北国大地 无情的北风穿透了人们御寒的衣物 可怜虫们在冬夜中发出无助的哀嚎 “冻死宝宝了!” 这时 远处的天边出现了一位火焰之神 “我将赐予你们温暖和希望!” 只见他的身体中喷射出火焰之力 通过坚固的钢铁,传遍了千家万户 这时,只听见人们欢呼 “暖气来啦!” 任务描述 虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很低. 小R的

P4930「FJ2014集训」采药人的路径

题目:P4930「FJ2014集训」采药人的路径 思路: 这篇不算题解,是让自己复习的,什么都没说清楚. 很久没有写点分治了,以前为了赶课件学的太急,板子都没打对就照着题解写题,导致学得很不扎实. 这道题差不多是在郭老师的指导下一点点凑出来的,还是没能自己完整写出一道题,惭愧. 这道题大意是:给出一棵边权为0/1的树,求满足以下条件的路径总数:0的个数等于1的个数,且路径上存在一点到路径两端也满足该条件. 这种求路径总数的题,可以想到用点分治. 把0看作-1,就可以转化为路径边权和为0. 如果没

南校五天集训游记

住四人间,我爽了 宿舍开灯有莫名的延迟??? 上床的梯子横杆很细,巨痛!!!\(SP\) \(\nearrow\) \(FA\) \(\searrow\) 大家在宿舍里不断发~财~(\(fafafa\)) 饭菜很便宜,早饭六元,午饭晚饭八元(因为我们被归为了国庆留校生) 山大附中和石门也来听,还有润德的一个小伙子,总共\(28\)人 被初中学长爆踩 \(Day3\)热身赛因\(Win10\)更新卡我半小时??? \(ysq\):留了长发(因为以前\(zzj\)不让留???),还有终极蛇皮笑声,\

MICS:副本和纠删码混合存储系统

摘要 云存储系统的三个指标: 高可靠性,低存储开销,高读写性能. 这三个指标是没有办法同一时候满足的,许多时候须要进行tradeoff. 副本系统和纠删码是两种在存储系统中广泛使用的策略,它们在保证高可靠性的前提下,选择了不同极端的tradeoff. 副本存储开销大,但性能较好.纠删码存储开销低.但性能较差.本文提出了MICS系统.它将一个对象以两种形式存储,一种採用副本.一种採用分片纠删码,不仅如此.还设计了针对这种hyprid结构的精细的读写协议. 在服务使用者的角度.MICS通过PRAM一