tarjan

牛客CSP-S提高组赛前集训营2 T2沙漠点列

我只是一个虾纸丫 提交于 2019-12-03 05:12:19
原题链接 算法不难,比赛的时候就和cyc大佬一起yy了正解,不过因为交的时候比较急(要回寝室惹),我有两数组开错大小直接爆到50,cyc大佬则只把文件输入关了一半,直接爆零(╯ ̄Д ̄)╯┻━┻ 要尽量使 \(k\) 次删边都能有贡献,那么很容易就想到割边。 所以我们先用 \(\mathtt{tarjan}\) 跑出所有割边,而每一条割边都能产生 \(1\) 的贡献,因此有 \(sum_{bridge}\) 条割边,就能增加 \(sum_{bridge}\) 个连通块。 若 \(k \leqslant sum_{bridge}\) ,那么最后的答案就是 \(k + s\) (设原来的图有 \(s\) 个连通块)。 若 \(k > sum_{bridge}\) ,那么先删去这些割边,则剩下 \(k' = k - sum_{bridge}\) 条删边的次数。 然后我们考虑剩下的图该怎么去删边使贡献最大。 很容易发现删去割边后的图就是单个简单环或多个以点连接的简单环的集合。 对于多个以点连接的简单环,实际上我们可以把这多个连接的环拆成多个单环,如下图所示: 因为虽然将多个环拆开来会多出几个点,但是与此同时也增加了相同数目的连通块,因此对拆开后的多个单环进行删边的最大贡献是与原图相同的。 然后我们考虑怎么在这单环集合中删边使得贡献最大化,显然对于一个环

杀人游戏(tarjan思维好题)

一曲冷凌霜 提交于 2019-12-03 04:57:00
P4819 [中山市选]杀人游戏 分析: 这种题先从简单情况分析:如果是一条链:1->2->3->4 直接查入度为0的即可:因为知道1,就知道2,如果2是杀手,结束。 否则去查证2(因为已知2不是杀手 所以这一步是不需要花费被杀的风险的!!) 以此类推。 最后的答案就是1-(1/n)*ans 一条链只需要查一个入度为0的点,那么如果有一个孤立的环呢? 显然需要查环中任意一个点即可。所以可以用tarjan缩点后,求入度为0的点即可。 但是这道题还有很多其他的坑: eg:100 0 如果前99个人都查完了,第100个人就可以不用查了 考虑什么时候可以不用查:当一个点入度为0,并且它连的所有点入度都不为1(也就是说其他点可以通过另一个入度为0的点查到) 并且它的siz==1(是一个孤立的点,否则环中必须查一个点) 特判一下即可。 #include<bits/stdc++.h> using namespace std; #define ri register int #define N 100005 int n,m,dfn[N],low[N],stk[N],flag[N],bel[N],ru[N],Ti=0,tot=0,top=0,siz[N]; vector<int> e[N]; vector<int> h[N]; void tarjan(int u) { dfn[u]=low[u]=+

【2019.10.31】nowcoder提高组赛前训练2

偶尔善良 提交于 2019-12-03 04:21:45
服务器需求 我觉得我考场上也想不到 \(ans=max(a_i,ceil(sum/m))\) 模拟的话 每加一台服务器就是选择最大需求消1 总的就需要 \(ceil(sum/m)\) 考虑有一天需求量贼大 其他所有的天数都做完了他还有剩的(因为一次操作只能消掉一天) 好叭还是感性理解一下 int n,m,q,a[N]; ll sum; multiset<ll>s; multiset<ll>::iterator its; int main(){ #ifndef ONLINE_JUDGE freopen("T1.txt","r",stdin); #endif rd(n),rd(m),rd(q); for(int i=1;i<=n;++i) rd(a[i]),sum+=(ll)a[i],s.insert(-a[i]); printf("%lld\n",max(-*s.begin(),(ll)(ceil((double)sum/m)))); for(int i=1,x,y;i<=q;++i){ rd(x),rd(y); its=s.find(-a[x]),s.erase(its); s.insert(-y),sum+=y-a[x],a[x]=y; printf("%lld\n",max(-*s.begin(),((ll)ceil((double)sum/m)))); } return 0;

图论总结tarjan算法

匿名 (未验证) 提交于 2019-12-03 00:41:02
tarjan算法,是一个可以在有向图中找到强连通分量的的算法。 首先你要了解什么是强连通,以及什么是强连通分量。 下面是我给的简释: 一、强连通。 二、强连通子图。 三、强连通分量 极大的强连通子图。 解释: 强连通分量 百度百科 好的,那么现在就有一个问题: 输入:一个图有向图。 输出:它每个强连通分量。 用tarjan算法怎么实现呢? 先给出几个变量的意义: 1.DFN[i]表示第几个搜索到的; 2.LOW[i]表示从搜索的路返回,最多能走到哪里。 3.STACK[i]表示一个栈。 输出了一个图,长这样: xiam下面几张图是深搜的过程:(假设我们从第一个点开始搜) 如下图:搜到6,走不动了,开始回溯。然后6出栈。6节点就是一个强连通分量。 于是 有了下图:回溯到3节点,操作不动了,3出栈。三就是一个强连通分量。 4走过了,于是继续操作至下图: 回溯到2,然后三走过,继续走5,五再继续操作,6走过且有DFN[6]!=LOW[6],走1; 发现DFN[1]=LOW[1] 可以说明找到环了,就找到了一个强连通分量 LOW[4]=1; 然后还有一个栈内的搜索图,就是什么时候出栈,这个你可以自己画一下,就可以明白了。 然后最后栈里面剩下来的,就是所求的qian强连通分量。 好,下面以之前的那一道例题作为实战:(就是之前的那一道题) 输入n,m; 表示有n个点,m条边,下面输入m条边

Tarjan 割边(桥)

匿名 (未验证) 提交于 2019-12-03 00:40:02
// Tarjan 割边 // 当dfn[u]<low[v]时u与v之间的边为割边 #include<iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> using namespace std; int n,m,cnt,ans,head[ 10001 ]; int dot,dfn[ 10001 ],low[ 10001 ]; int cut[ 200001 ]; struct uio{ int from ,to,next,id; }edge[ 200001 ]; void add( int x, int y) { edge[ ++cnt].next= head[x]; edge[cnt]. from = x; edge[cnt].to = y; edge[cnt].id = cnt; head[x] = cnt; } void tarjan( int x, int fa) { dfn[x] =low[x]=++ dot; for ( int i=head[x];i;i= edge[i].next) { int y= edge[i].to; if (! dfn[y]) { tarjan(y,x); low[x] = min(low

Popular Cows(tarjan + 缩点)

匿名 (未验证) 提交于 2019-12-03 00:30:01
Language:Default Popular Cows Time Limit: Memory Limit: Total Submissions: Accepted: Description Input Output Sample Input 3 3 1 2 2 1 2 3 Sample Output 1 【题意】: tarjia算法了解一下 https://www.byvoid.com/zhs/blog/scc-tarjan https://blog.csdn.net/qq_34374664/article/details/77488976 AC代码: #include<cstdio> #include<iostream> #include<cstring> #include<stack> #include<cmath> using namespace std; const int maxn=1e4+50; const int maxm=5e4+50; int head[maxn],LOW[maxn],DFN[maxn],id[maxn],cnt[maxn]; bool mark[maxn]; int N,M,time=0,scc=0; stack<int>sta; struct edge_t{ int to,next; }edge[maxm]; void init() {

tarjan学习笔记

匿名 (未验证) 提交于 2019-12-03 00:17:01
首先是求强连通分量: 这个的思路大致就是每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。 定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号。 代码如下(伪): 1 void tarjan(int x) 2 { 3 dfn[x]=low[x]=++cnt; 4 instack[x]=1; 5 s.push(x); 6 int y; 7 for(int i=head[x];i;i=e[i].nxt) 8 { 9 y=e[i].to; 10 if(!dfn[y]) 11 { 12 tarjan(y); 13 low[x]=min(low[x],low[y]); 14 } 15 else if(instack[y]) low[x]=min(low[x],dfn[y]); 16 } 17 y=0; 18 if(dfn[x]==low[x]) 19 { 20 tot++; 21 while(x!=y) 22 { 23 y=s.top(); 24 s.pop(); 25 instack[y]=0; 26 belong[y]=tot; 27 } 28 } 29 } 30 void solve() 31 { 32 tot=cnt=0; 33

tarjan算法――割边(桥)

匿名 (未验证) 提交于 2019-12-03 00:10:02
模板: 1 int vis [ maxn ], dfn [ maxn ], low [ maxn ]; 2 int n , m , a [ maxn ][ maxn ], lay ; 3 #define mp make_pair 4 #define fi first 5 #define se second 6 vector < pair < int , int > > ans ; 7 void tarjan ( int u , int father ) { 8 low [ u ]= dfn [ u ]=++ lay ; 9 vis [ u ]= 1 ; 10 for ( int v = 0 ; v < n ; v ++) { 11 if ( v == father ) continue ; 12 if ( a [ u ][ v ]&&! vis [ v ]) { 13 tarjan ( v , u ); 14 low [ u ]= min ( low [ u ], low [ v ]); 15 if ( dfn [ u ]< low [ v ]) 16 ans . push_back ( mp ( min ( u , v ), max ( u , v ))); 17 } 18 else if ( a [ u ][ v ]) low [ u ]= min ( dfn [ v ],

受欢迎的牛(Tarjan缩点模板)

匿名 (未验证) 提交于 2019-12-03 00:07:01
#include<cstdio> #include<cstring> #include<stack> using namespace std; int n,m,head[10005],vis[10005],dfn[10005], low[10005],color[10005],num[10005],out[10005]; int sum,cnt,tot,jia,ans; stack<int> s; struct edge{ int v,next; }e[50005]; inline void add(int u,int v){ e[++cnt].v=v; e[cnt].next=head[u]; head[u]=cnt; } inline void tarjan(int u){ vis[u]=1; s.push(u); dfn[u]=low[u]=++tot; for(int i=head[u];i!=-1;i=e[i].next){ int v=e[i].v; if(!dfn[v]){ tarjan(v); low[u]=min(low[v],low[u]); } else if(vis[v])low[u]=min(low[v],low[u]); } if(dfn[u]==low[u]){ color[u]=++sum; vis[u]=0; while(1){ int x=s

危险道路(Tarjan+割边/桥)

匿名 (未验证) 提交于 2019-12-02 23:55:01
题目描述 天凯是苏联的总书记。苏联有n个城市,某些城市之间修筑了公路。任意两个城市都可以通过公路直接或者间接到达。 天凯发现有些公路被毁坏之后会造成某两个城市之间无法互相通过公路到达。这样的公路就被称为dangerous pavement。 为了防止美帝国对dangerous pavement进行轰炸,造成某些城市的地面运输中断,天凯决定在所有的dangerous pavement驻扎重兵。可是到底哪些是dangerous pavement呢?你的任务就是找出所有这样的公路。 输入格式 第一行n,m(1<=n<=100000, 1<=m<=300000),分别表示有n个城市,总共m条公路。 以下m行每行两个整数a, b,表示城市a和城市b之间修筑了直接的公路。 输出格式 输出有若干行。每行包含两个数字a,b(a < b),表示 < a,b >是dangerous pavement。请注意:输出时,所有的数对< a,b>必须按照a从小到大排序输出;如果a相同,则根据b从小到大排序。 输入 6 6 1 2 2 3 2 4 3 5 4 5 5 6 输出 1 2 5 6 Tarjan算法割边的模板 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N=1e5+5; 5 int n,m,dep; 6 int dfn