AtCoder AGC033F Adding Edges (图论)

2024-02-15 15:32

本文主要是介绍AtCoder AGC033F Adding Edges (图论),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

------------恢复内容开始------------

题目链接

https://atcoder.jp/contests/agc033/tasks/agc033_f

题解

又被神仙题搞自闭了……
首先让我们来读错题:把题面里的"in some order"改成"in this order"! 似乎变简单了很多!
显然一条边\((u,v)\)会被产生当且仅当在原图上存在从\(u\)\(v\)的一条路径,使得这条路径上的点依次位于树上的一条路径上。然后我们可以从每个点开始BFS或DFS确定答案。
但是现在的题意是"in some order", 没有对路径上三个点的经过顺序进行约束。那么我们考虑把它强行转化成顺序确定的情况。
假设存在\((a,b,c)\)满足在树上\(b\)\(a,c\)的路径上且在图上\(a,b\)\(a,c\)之间都有连边,那么把\(a,c\)的连边去掉,连上\(b,c\)的边。假设我们这样操作直到不能操作为止,那么新的图产生的边和原图是一样的,且新图加边过程中三个点在树的路径上出现的顺序一定和"in this order"保持一致,然后直接采用刚才的做法做即可。
现在考虑如何做上面所说的操作。用\(f[u][v]\)维护以\(u\)为根时如果添加一条\((u,v)\)的边,那么实际上\(u\)端点会被哪个点替代,然后每次新加一条图的边,先把这条边缩到最短,然后再分别在以\(u\)为根\(v\)子树内和以\(v\)为根\(u\)子树内找其他能缩的边以及更新\(f\),详见代码。
复杂度分析:发现我们每遍历一个点,要么会缩一条边,要么会使得\(f\)数组里\(f[u][v]=u\)的个数减少\(1\), 故总时间复杂度\(O(n^2+nm)\).

代码

#include<bits/stdc++.h>
#define llong long long
#define mkpr make_pair
#define pii pair<int,int>
#define riterator reverse_iterator
using namespace std;inline int read()
{int x = 0,f = 1; char ch = getchar();for(;!isdigit(ch);ch=getchar()) {if(ch=='-') f = -1;}for(; isdigit(ch);ch=getchar()) {x = x*10+ch-48;}return x*f;
}const int N = 2e3;
struct Edge
{int v,nxt;
} e[(N<<1)+3];
int fe[N+3];
int fa[N+3][N+3];
int f[N+3][N+3];
int n,m,en,ans;void addedge(int u,int v)
{en++; e[en].v = v;e[en].nxt = fe[u]; fe[u] = en;
}void dfs1(int rt,int u)
{for(int i=fe[u]; i; i=e[i].nxt){int v = e[i].v; if(v==fa[rt][u]) continue;fa[rt][v] = u;dfs1(rt,v);}
}void addedgeg(int u,int v)
{if(f[u][v]==v||f[v][u]==u) {return;}
//  printf("addedgeg %d %d %d %d\n",u,v,f[u][v],f[v][u]);if(f[u][v]!=u) {addedgeg(f[u][v],v); return;}if(f[v][u]!=v) {addedgeg(u,f[v][u]); return;}f[u][v] = v,f[v][u] = u;vector<pii> ext; queue<int> que;que.push(v);while(!que.empty()){int cu = que.front(); que.pop();for(int i=fe[cu]; i; i=e[i].nxt){int cv = e[i].v; if(cv==fa[u][cu]) continue;if(f[u][cv]==u) {f[u][cv] = v; que.push(cv);}else {ext.push_back(mkpr(v,cv));}}}que.push(u);while(!que.empty()){int cu = que.front(); que.pop();for(int i=fe[cu]; i; i=e[i].nxt){int cv = e[i].v; if(cv==fa[v][cu]) continue;if(f[v][cv]==v) {f[v][cv] = u; que.push(cv);}else {ext.push_back(mkpr(u,cv));}}}for(int i=0; i<ext.size(); i++){addedgeg(ext[i].first,ext[i].second);}
}void dfs2(int rt,int u,int prv)
{if(u!=rt && f[prv][u]==u) {ans++; prv = u;}for(int i=fe[u]; i; i=e[i].nxt){int v = e[i].v; if(v==fa[rt][u]) continue;dfs2(rt,v,prv);}
}int main()
{scanf("%d%d",&n,&m);for(int i=1; i<n; i++) {int u,v; scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u);}for(int i=1; i<=n; i++){dfs1(i,i);}for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) f[i][j] = i;for(int i=1; i<=m; i++){int x,y; scanf("%d%d",&x,&y);addedgeg(x,y);}for(int i=1; i<=n; i++){dfs2(i,i,i);}printf("%d\n",ans>>1);return 0;
}

------------恢复内容结束------------

这篇关于AtCoder AGC033F Adding Edges (图论)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/711790

相关文章

AtCoder Beginner Contest 370 Solution

A void solve() {int a, b;qr(a, b);if(a + b != 1) cout << "Invalid\n";else Yes(a);} B 模拟 void solve() {qr(n);int x = 1;FOR(i, n) FOR(j, i) qr(a[i][j]);FOR(i, n) x = x >= i ? a[x][i]: a[i][x];pr2(

【代码随想录训练营第42期 续Day52打卡 - 图论Part3 - 卡码网 103. 水流问题 104. 建造最大岛屿

目录 一、做题心得 二、题目与题解 题目一:卡码网 103. 水流问题 题目链接 题解:DFS 题目二:卡码网 104. 建造最大岛屿 题目链接 题解:DFS  三、小结 一、做题心得 也是成功补上昨天的打卡了。 这里继续图论章节,还是选择使用 DFS 来解决这类搜索问题(单纯因为我更熟悉 DFS 一点),今天补卡的是水流问题和岛屿问题。个人感觉这一章节题对于刚

图论篇--代码随想录算法训练营第五十二天打卡| 101. 孤岛的总面积,102. 沉没孤岛,103. 水流问题,104.建造最大岛屿

101. 孤岛的总面积 题目链接:101. 孤岛的总面积 题目描述: 给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿指的是由水平或垂直方向上相邻的陆地单元格组成的区域,且完全被水域单元格包围。孤岛是那些位于矩阵内部、所有单元格都不接触边缘的岛屿。 现在你需要计算所有孤岛的总面积,岛屿面积的计算方式为组成岛屿的陆地的总数。 解题思路: 从周边找到陆地,然后通过 dfs或者bfs 将

AtCoder Beginner Contest 369 D - Bonus EXP 动态规划

原题链接: https://atcoder.jp/contests/abc369/tasks/abc369_d 思路:   这道题为什么要用动态规划呢,其实,对于第i个怪物,我们有打与不打两种处理方式,而对于打,我们是获得两倍的经验值,还是一倍的经验值,与我们打了奇数只怪物还是打了偶数只怪物有关了,因此我们定义dp[i][0] 为前i只怪物总共打了偶数次,dp[i][1] 为前i只怪物总

代码随想录 刷题记录-28 图论 (5)最短路径

一、dijkstra(朴素版)精讲 47. 参加科学大会 思路 本题就是求最短路,最短路是图论中的经典问题即:给出一个有向图,一个起点,一个终点,问起点到终点的最短路径。 接下来讲解最短路算法中的 dijkstra 算法。 dijkstra算法:在有权图(权值非负数)中求从起点到其他节点的最短路径算法。 需要注意两点: dijkstra 算法可以同时求 起点到所有节点的最短路径权值不

图论篇--代码随想录算法训练营第五十一天打卡| 99. 岛屿数量(深搜版),99. 岛屿数量(广搜版),100. 岛屿的最大面积

99. 岛屿数量(深搜版) 题目链接:99. 岛屿数量 题目描述: 给定一个由 1(陆地)和 0(水)组成的矩阵,你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。你可以假设矩阵外均被水包围。 解题思路: 1、每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。 2、遇到一个没有遍历过的节点陆地,计数器就加一,然后把该节点陆地所能遍历到的陆地都

图论篇--代码随想录算法训练营第五十天打卡| 深度优先搜索理论基础,98. 所有可达路径,广度优先搜索理论基础

深度优先搜索理论基础 DFS模板: void dfs(参数) {if (终止条件) {存放结果;return;}for (选择:本节点所连接的其他节点) {处理节点;dfs(图,选择的节点); // 递归回溯,撤销处理结果}} 98. 所有可达路径 题目链接:98. 所有可达路径 题目描述: 给定一个有 n 个节点的有向无环图,节点编号从 1 到 n。请编写一个函数,找出并返回所

数据结构实验图论:基于邻接矩阵/邻接表的广度优先搜索遍历(BFS)

数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历 Time Limit: 1000MS Memory limit: 65536K 题目描述 给定一个无向连通图,顶点编号从0到n-1,用广度优先搜索(BFS)遍历,输出从某个顶点出发的遍历序列。(同一个结点的同层邻接点,节点编号小的优先遍历) 输入 输入第一行为整数n(0< n <100),表示数据的组数。 对于

代码随想录算法训练营第六十二天 | 图论part11

97. 小明逛公园 #include <iostream>#include <vector>#include <climits>#include <fstream>using namespace std;void floyd(vector<vector<vector<int>>>& grid) {int n = grid.size() - 1;for (int k = 1; k <= n;

图论 求有向图的所有强连通分量 kosaraju算法

一、问题 如何找到有向图(a)中的所有强连通分量,如图(b)    二、kosaraju算法 Kosaraju的算法(又称为–Sharir Kosaraju算法)是一个线性时间(linear time)算法找到的有向图的强连通分量。   1. 原理 它利用了一个事实,逆图(与各边方向相同的图形反转, transpose graph)有相同的强连通分量的原始图。   2. 逆图