「刷题笔记」Tarjan
信息传递
讲个笑话:我之前用并查集求最小环过的这题,然后看见题目上有个\(tarjan\)标签
留下了深刻的印象:\(tarjan\)就是并查集求最小环
丢死人了
那么这题题意也很明确了,就是求一个最小环,并查集啥的就不想他了,考虑一下\(tarjan\)的做法
这道题里,就是我们求出每个强连通分量,然后看每个强连通分量最小大小是多少就好
贴一下板子qwq
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define ZZ_zuozhe int main()
#define E 200050
struct edge
{
ll u,v;
}e[E];
ll tot,head[E],next[E];
void add(ll a,ll b)
{
++tot;
e[tot].u=a;
e[tot].v=b;
next[tot]=head[a];
head[a]=tot;
}
ll n,t;
ll dfs[E],low[E],vis[E],cnt=0;
stack<ll> S;
ll pcn=0,pp[E];
void tarjan(ll u)
{
dfs[u]=low[u]=++cnt;
S.push(u);
vis[u]=1;
for(int i=head[u];i;i=next[i])
{
ll v=e[i].v;
if(!dfs[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v])low[u]=min(low[u],dfs[v]);
}
if(dfs[u]==low[u])
{
++pcn;
ll tmp;
do{tmp=S.top();S.pop();pp[pcn]++;vis[tmp]=0;}while(tmp!=u);
}
}
ZZ_zuozhe
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&t);
add(i,t);
}
for(int i=1;i<=n;i++)
{
if(!dfs[i])tarjan(i);
}
ll ans=E+1;
for(int i=1;i<=pcn;i++)
{
//cout<<pp[i]<<endl;
if(pp[i]>1)ans=min(ans,pp[i]);
}
printf("%lld",ans);
return 0;
}
受欢迎的牛
由题意,我们首先可以得出,所有满足题意的牛都是在同一个强连通分量里的,但是给出的图中有许多强连通分量,哪些才是满足要求的呢?
首先,会不会有两个及以上满足要求的强连通分量呢?显然不行,因为那样就不符合强连通分量的定义了:
有向图的极大强连通子图,称为强连通分量
所以,我们只需要找出一个满足要求的强连通分量。
考虑要满足的要求,那么所有强连通分量都是有一条路通向我们所求的这个强连通分量的,再考虑前面强连通分量的定义,就会发现我们所求的这个强联通分量出度必须为\(0\)
与此同时,如果出现了多个出度为\(0\)的强连通分量,那么这两个强连通分量肯定是无法与彼此连通的,这种情况下,答案为\(0\)
同时,如果只有一个出度为\(0\)的强连通分量,那么答案即为这个强连通分量中包含点的个数。
码很好打,这里只是放一下,但这题思路着实挺有意思的awa
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define ZZ_zuozhe int main()
#define N 10005
#define E 500005
struct edge
{
ll u,v;
}e[E];
ll tot=0,head[E],next[E];
void add(ll a,ll b)
{
++tot;
e[tot].u=a;
e[tot].v=b;
next[tot]=head[a];
head[a]=tot;
}
ll n,m,a,b;
ll dfs[E],low[E],vis[E],cnt=0;
ll pcn=0,pp[E],col[E],out[E];
stack<ll>S;
void tarjan(ll u)
{
dfs[u]=low[u]=++cnt;
vis[u]=1;
S.push(u);
for(int i=head[u];i;i=next[i])
{
ll v=e[i].v;
if(!dfs[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v])low[u]=min(low[u],dfs[v]);
}
if(low[u]==dfs[u])
{
++pcn;
ll tmp;
do{tmp=S.top();S.pop();vis[tmp]=0;pp[pcn]++;col[tmp]=pcn;}while(tmp!=u);
}
}
ZZ_zuozhe
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%lld%lld",&a,&b);
add(a,b);
}
for(int i=1;i<=n;i++)
{
if(!dfs[i])tarjan(i);
}
for(int i=1;i<=n;i++)
{
for(int j=head[i];j;j=next[j])
{
if(col[i]!=col[e[j].v])out[col[i]]++;
}
}
bool flag=1;
ll ans=0;
for(int i=1;i<=pcn;i++)
{
if(out[i]==0)
{
if(flag)
{
ans=pp[i];
flag=0;
}
else
{
printf("0\n");
return 0;
}
}
}
printf("%lld\n",ans);
return 0;
}
拓展:
一个现在还并没有看懂的证明qaq
(感觉这个证明多加了个无环的条件,反正就先把所有\(DAG\)换成有向图理解吧qaq
[APIO2009]抢掠计划
tarjan缩点+\(spfa\)最长路
他可以经过同一路口或道路任意多次。
这个条件的存在告诉我们,因为有向图强连通分量中的点可以互相到达,那么如果走到了强连通分量其中的一个点,其实就相当于这个强连通分量中的点都走到了,既然如此,我们不妨将每个强连通分量看成一个点,并保留那些跨分量的边,再在得到的新图上用\(spfa\)跑最长路,最后枚举每个酒吧所处的强联通分量的\(dis\),取最大值即可得到答案。
缩点的过程是这样的:\(tarjan\)函数中,需要给各个结点染色,之后,先将原来存的边清空,再枚举原来的每条边(需要之前将两端点另存),如果发现他是跨分量的边,就把他两端点所在的强连通分量编号连边(注意保留原有方向),就建成了新图,应该是一个\(DAG\)。
然后就是正常的\(spfa\)了
考虑到降智严重的我有时会突然忘\(spfa\)板子,贴一下代码……
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define ZZ_zuozhe int main()
#define E 500050
struct edge
{
ll u,v,w;
}e[E];
ll tot=0,head[E],next[E];
void add(ll a,ll b,ll c)
{
tot++;
e[tot].u=a;
e[tot].v=b;
e[tot].w=c;
next[tot]=head[a];
head[a]=tot;
}
ll n,m,a[E],b[E],s,p,t;
ll w[E];
ll bar[E];
stack<ll> S;
ll vis[E],low[E],dfs[E],cnt=0;
ll pcn=0,pp[E],col[E];
void tarjan(ll u)
{
low[u]=dfs[u]=++cnt;
vis[u]=1;
S.push(u);
for(int i=head[u];i;i=next[i])
{
ll v=e[i].v;
if(!dfs[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v])low[u]=min(low[u],dfs[v]);
}
if(low[u]==dfs[u])
{
ll tmp;
++pcn;
do{tmp=S.top();S.pop();vis[tmp]=0;col[tmp]=pcn;pp[pcn]+=w[tmp];}while(tmp!=u);
}
}
ll dis[E];
queue<ll>Q;
void SPFA(ll s)
{
for(int i=1;i<=tot;i++)dis[i]=0;
Q.push(s);
dis[s]=pp[s];
//cout<<dis[s]<<endl;
vis[s]=1;
while(!Q.empty())
{
ll u=Q.front();Q.pop();
vis[u]=0;
for(int i=head[u];i;i=next[i])
{
ll v=e[i].v;
if(dis[v]<dis[u]+e[i].w)
{
dis[v]=dis[u]+e[i].w;
//cout<<dis[v]<<endl;
if(!vis[v])
{
Q.push(v);
vis[v]=1;
}
}
}
}
}
ZZ_zuozhe
{
//freopen("owo.in","r",stdin);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%lld%lld",&a[i],&b[i]);
add(a[i],b[i],0);
}
for(int i=1;i<=n;i++)scanf("%lld",&w[i]);
scanf("%lld%lld",&s,&p);
//cout<<p<<endl;
for(int i=1;i<=p;i++)
{
scanf("%lld",&t);
bar[i]=t;
//cout<<i<<' '<<<<endl;
}
for(int i=1;i<=n;i++)if(!dfs[i])tarjan(i);//cout<<i<<endl;
memset(e,0,sizeof e);
memset(head,0,sizeof head);
memset(next,0,sizeof next);
memset(vis,0,sizeof vis);
tot=0;
for(int i=1;i<=m;i++)
{
if(col[a[i]]!=col[b[i]])add(col[a[i]],col[b[i]],pp[col[b[i]]]);//cout<<a[i]<<' '<<b[i]<<' '<<col[a[i]]<<' '<<col[b[i]]<<' '<<pp[col[b[i]]]<<endl;
}
SPFA(col[s]);
ll ans=0;
for(int i=1;i<=p;i++)
{
//cout<<'\t'<<dis[col[bar[i]]]<<' '<<i<<' '<<bar[i]<<' '<<col[bar[i]]<<endl;
ans=max(ans,dis[col[bar[i]]]);
}
printf("%lld\n",ans);
return 0;
}
备用交换机
割点板子
求割点的算法也叫\(tarjan\)……不过似乎与求强连通分量那个有些微妙的差别,主要思想有相似之处
啊 这……我不知道有什么要讲了,贴一下这部分的板子吧qaq
void tarjan(ll u,ll fa)
{
dfn[u]=low[u]=++cnt;
ll ch=0;
for(int i=head[u];i;i=next[i])
{
ll v=e[i].v;
if(!dfn[v])
{
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]&&u!=fa)cut[u]=1;
if(u==fa)ch++;
}
low[u]=min(low[u],dfn[v]);
}
if(ch>=2&&u==fa)cut[u]=1;
}
Trick or Treat on the Farm 采集糖果
我震惊了,这个数据范围,我上来居然不想记搜……T飞了……
还有一个点就是要注意自环,不然会爆栈
其他没有特别要说的了,本来是个板子题,然而因为\(sb\)错误弄了大半天qaq
关于low和dfn的问题……
上午刚会板子的时候教练问到了这个问题,其实就是求强连通分量的时候他如果搜到了到过的点,用来更新的不管是\(low\)还是\(dfn\)都肯定比当前\(low\)小,造成的结果也就都是这个点不会被当作根弹掉,所以实际上没啥影响
然后做割点的时候在题解区看到了这个,里面的解释挺详细的awa,总之就是求割点时换成\(low\)就会\(wa\),不过既然用\(dfn\)肯定不会错,又何必要改呢qaq,总之以后注意不要写错就是了
「刷题笔记」Tarjan的更多相关文章
- 「刷题笔记」AC自动机
自动AC机 Keywords Research 板子题,同luoguP3808,不过是多测. 然后多测不清空,\(MLE\)两行泪. 板子放一下 #include<bits/stdc++.h&g ...
- 「刷题笔记」DP优化-状压-EX
棋盘 需要注意的几点: 题面编号都是从0开始的,所以第1行实际指的是中间那行 对\(2^{32}\)取模,其实就是\(unsigned\ int\),直接自然溢出啥事没有 棋子攻击范围不会旋转 首先, ...
- 「刷题笔记」LCA问题相关
板子 ll lg[40]; ll dep[N],fa[N][40]; ll dis[N]; void dfs(ll u,ll f) { dep[u]=dep[f]+1; fa[u][0]=f; for ...
- 「刷题笔记」哈希,kmp,trie
Bovine Genomics 暴力 str hash+dp 设\(dp[i][j]\)为前\(i\)组匹配到第\(j\)位的方案数,则转移方程 \[dp[i][j+l]+=dp[i-1][j] \] ...
- 《Data Structures and Algorithm Analysis in C》学习与刷题笔记
<Data Structures and Algorithm Analysis in C>学习与刷题笔记 为什么要学习DSAAC? 某个月黑风高的夜晚,下班的我走在黯淡无光.冷清无人的冲之 ...
- Python 刷题笔记
Python 刷题笔记 本文记录了我在使用python刷题的时候遇到的知识点. 目录 Python 刷题笔记 选择.填空题 基本输入输出 sys.stdin 与input 运行脚本时传入参数 Pyth ...
- ☕【JVM技术指南】「JVM总结笔记」Java虚拟机垃圾回收认知和调优的"思南(司南)"【下部】
承接上文 (完结撒花1-52系列)[JVM技术指南]「JVM总结笔记」Java虚拟机垃圾回收认知和调优的"思南(司南)"[上部] 并行收集器 并行收集器(也称为吞吐量收集器)是类似 ...
- PTA刷题笔记
PTA刷题记录 仓库地址: https://github.com/Haorical/Code/tree/master/PTA/GPLT 两周之内刷完GPLT L2和L3的题,持续更新,包括AK代码,坑 ...
- 看完互联网大佬的「LeetCode 刷题手册」, 手撕了 400 道 Leetcode 算法题
大家好,我是 程序员小熊 ,来自 大厂 的程序猿.相信绝大部分程序猿都有一个进大厂的梦想,但相较于以前,目前大厂的面试,只要是研发相关岗位,算法题基本少不了,所以现在很多人都会去刷 Leetcode ...
随机推荐
- [Luogu P2824] [HEOI2016/TJOI2016]排序 (线段树+二分答案)
题面 传送门:https://www.luogu.org/problemnew/show/P2824 Solution 这题极其巧妙. 首先,如果直接做m次排序,显然会T得起飞. 注意一点:我们只需要 ...
- [Luogu P3986] 斐波那契数列 (逆元)
题面 传送门:https://www.luogu.org/problemnew/show/P3986 Solution 这是一道很有意思的数论题. 首先,我们可以发现直接枚举a和b会T的起飞. 接下来 ...
- MySQL中没有FULL OUTER JOIN的处理
FULL OUTER JOIN:SELECT column_name(s)FROM table1FULL OUTER JOIN table2ON table1.column_name=table2.c ...
- Apache Kylin远程代码执行漏洞复现(CVE-2020-1956)
Apache Kylin远程代码执行(CVE-2020-1956) 简介 Apache Kylin 是美国 Apache 软件基金会的一款开源的分布式分析型数据仓库.该产品主要提供 Hadoop/Sp ...
- leetcode75:search-a-2d-matrix
题目描述 请写出一个高效的在m*n矩阵中判断目标值是否存在的算法,矩阵具有如下特征: 每一行的数字都从左到右排序 每一行的第一个数字都比上一行最后一个数字大 例如: 对于下面的矩阵: [ [1, 3, ...
- 记录一些API(持续更新)
//对response进行编解码URLEncoder.encode(string,"UTF-8");//ts检查checkbox是否为选中状态$event.target.check ...
- 最全总结 | 聊聊 Python 办公自动化之 Word(上)
1. 前言 日常自动化办公中,使用 Python 真的能做到事半功倍! 在上一个系列中,我们对 Python 操作 Excel 进行了一次全面总结 最全总结 | 聊聊 Python 办公自动化之 Ex ...
- SpringBoot整合JWT实战详解
jwt 介绍就不多说了,下面通过代码演示开发过程中jwt 的使用. (1)在pom.xml中引入对应的jar <dependency> <groupId>io.jsonwebt ...
- python_sys.argv的使用
# sys.argv练习 # 写一个python脚本,在cmd里执行 # python xxx.py 用户名 密码 cp 文件路径 目的地址 # python xxx.py alex sb cp D: ...
- Docker(33)- 如何修改 docker 容器的端口映射
如果你还想从头学起 Docker,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1870863.html 问题背景 docker run ...