系列索引:

树链剖分

https://oi-wiki.org/graph/heavy-light-decomposition/

  • qRange:将树从 \(x\) 到 \(y\) 结点最短路径上所有节点的值都加上 \(val\)
  • updRange:求树从 \(x\) 到 \(y\) 结点最短路径上所有节点的值之和
  • qSon:将以 \(x\) 为根节点的子树内所有节点值都加上 \(val\)
  • updSon:求以 \(x\) 为根节点的子树内所有节点值之和

时间复杂度 \(O(n\log^2n)\)。

int w[N], wt[N];
int t[N<<2], laz[N<<2];
int son[N], id[N], fa[N], dep[N], siz[N], top[N]; inline void pushdown(int k, int len) {
laz[k<<1]+=laz[k];
laz[k<<1|1]+=laz[k];
t[k<<1] = (t[k<<1] + laz[k]*(len-(len>>1))) % MOD;
t[k<<1|1] = (t[k<<1|1] + laz[k]*(len>>1)) % MOD;
laz[k]=0;
}
void build(int k, int l, int r) {
if (l==r) {t[k] = wt[l] % MOD; return; }
int mid=(l+r)>>1;
build(k<<1, l, mid);
build(k<<1|1, mid+1, r);
t[k] = (t[k<<1] + t[k<<1|1]) % MOD;
}
int query(int k, int l, int r, int x, int y) {
if (x<=l && r<=y) {return t[k]; }
if (laz[k]) pushdown(k, r-l+1);
int mid=(l+r)>>1, res=0;
if (x<=mid) res = (res + query(k<<1, l, mid, x, y)) % MOD;
if (y>mid) res = (res + query(k<<1|1, mid+1, r, x, y)) % MOD;
return res;
}
void update(int k, int l, int r, int x, int y, int val) {
if (x<=l && r<=y) {laz[k]+=val, t[k]+=val*(r-l+1); return; }
if (laz[k]) pushdown(k, r-l+1);
int mid=(l+r)>>1;
if (x<=mid) update(k<<1, l, mid, x, y, val);
if (y>mid) update(k<<1|1, mid+1, r, x, y, val);
t[k] = (t[k<<1] + t[k<<1|1]) % MOD;
} inline int qRange(int x, int y) {
int ans=0;
while (top[x]!=top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
ans = (ans + query(1, 1, n, id[top[x]], id[x])) % MOD;
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x, y);
ans = (ans + query(1, 1, n, id[x], id[y])) % MOD;
return ans;
}
inline void updRange(int x, int y, int val) {
val %= MOD;
while (top[x]!=top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
update(1, 1, n, id[top[x]], id[x], val);
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x, y);
update(1, 1, n, id[x], id[y], val);
}
inline int qSon(int x) {
return query(1, 1, n, id[x], id[x]+siz[x]-1);
}
inline void updSon(int x, int val) {
update(1, 1, n, id[x], id[x]+siz[x]-1, val);
} void dfs1(int x, int f, int d) {
dep[x] = d, fa[x] = f, siz[x] = 1;
int heavy=-1;
for (rint i=head[x]; i; i=nex[i]) {
int &y=to[i]; if (y==f) continue;
dfs1(y, x, d+1);
siz[x]+=siz[y];
if (siz[y]>heavy) son[x]=y, heavy=siz[y];
}
}
void dfs2(int x, int tp) {
id[x]=++id[0], wt[id[0]]=w[x], top[x]=tp;
if (!son[x]) return;
dfs2(son[x], tp); // heavy son first
for (rint i=head[x]; i; i=nex[i]) {
int &y=to[i]; if (y==fa[x] || y==son[x]) continue;
dfs2(y, y); // light son with new chain
}
} dfs1(root, 0, 1);
dfs2(root, root);
build(1, 1, n);

求树的重心

https://oi-wiki.org/graph/tree-misc/

拓扑排序

在顶点活动网 (Activity On Vertex network, AOV) 中,若不存在回路,则所有活动可排列成一个线性序列,使得每个活动的所有前驱活动都排在该活动的前面,我们把此序列叫做拓扑序列 (Topological order),由 AOV 网构造拓扑序列的过程叫做拓扑排序 (Topological sort)。AOV 网的拓扑序列不是唯一的,满足上述定义的任一线性序列都称作它的拓扑序列。

Kahn 算法:

将入度为 0 的边组成一个集合 \(S\),每次从 \(S\) 里面取出一个顶点 \(v\) (可以随便取) 放入 \(L\),然后遍历顶点 \(v\) 的所有边 \((u_1, v), (u_2, v), (u_3, v) \cdots\) 并删除,判断如果该边的另一个顶点在移除这一条边后入度为 0,那么就将这个顶点放入集合 \(L\) 中。

不断地重复取出顶点。

最后当集合为空后,就检查图中是否存在任何边。如果有,那么这个图一定有环路,否则返回 \(L\),\(L\) 中顺序就是拓扑排序的结果。

常用队列实现 \(S\) 集合。时间复杂度 \(O(V+E )\)。

int ind[N], topo[N], cnt;
queue<int> q; for (int i=1, a, b; i<=m; i++)
scanf("%d%d", &a, &b), add(a, b), ++ind[b];
for (int i=1; i<=n; i++) if (!ind[i]) q.push(i);
while (!q.empty()) {
int t = q.top(), q.pop(); topo[++cnt] = t;
for (int i=head[t]; i; i=nex[i]) {
--ind[to[i]];
if (!ind[to[i]]) q.push(to[i]);
}
}
if (cnt < n) printf("有环!")

强连通分量

在一个有向图中,如果某两点间都有互相到达的路径,那么称中两个点强连通,如果任意两点都强连通,那么称这个图为强连通图;一个有向图的极大强连通子图称为强连通分量。

一个强连通分量中的点一定处于搜索树中同一棵子树中。

Tarjan 算法:

  • low[] 表示这个点以及其子孙节点连的所有点中dfn最小的值.
  • s[] 表示当前所有可能能构成是强连通分量的点.
  • col[] 对强连通分量进行染色.
  • v[to[k]]==false 说明无论如何这个点也不能与u构成强连通分量,因为它不能到达u.
  • low[x]==dfn[x] 说明u点及u点之下的所有子节点没有边是指向u的祖先的了,即u点与它的子孙节点构成了一个最大的强连通图即强连通分量.
  • if (!dfn[i]) tarjan(i); Tarjan一遍不能搜完所有的点,因为存在孤立点. 所以我们要对一趟跑下来还没有被访问到的点继续跑Tarjan.

均摊时间复杂度 \(O(n)\).

int dfn[N], low[N], t, s[N], st;
int col[N], ct;
bool v[N]; void tarjan(int x) {
dfn[x]=low[x]=++t, s[++st]=x, v[x]=true;
for (int k=head[x]; k; k=nex[k]) {
if (dfn[to[k]]) {if (v[to[k]]) low[x]=min(low[x], dfn[to[k]]); }
else tarjan(to[k]), low[x]=min(low[x], low[to[k]]);
}
if (low[x]==dfn[x]) {
col[x]=++ct, v[x]=false;
while (s[st]!=x) col[s[st]]=ct, v[s[st--]]=false;
--st;
}
} for (int i=1; i<=n; ++i) if (!dfn[i]) tarjan(i);

[USACO06JAN] The Cow Prom:

for (rint i=1; i<=n; ++i) ++cnt[col[i]];
for (rint i=1; i<=ct; ++i) if (cnt[i]>1) ++ans;
printf("%d\n", ans);

缩点

缩点: 对于 贡献具有传递性 的题,因为强连通分量中的每两个点都是强连通的,可以将一个强连通分量当做一个 超级点,而点权按题意来定.

POJ2186 Popular Cows: 告诉你有n头牛,m个崇拜关系,并且崇拜具有传递性,如果a崇拜b,b崇拜c,则a崇拜c,求最后有几头牛被所有牛崇拜.

显然一个强联通分量内的所有点都是满足条件的,我们可以对整张图进行缩点,然后就简单了.

剩下的所有点都不是强连通的,现在整张图就是一个DAG(有向无环图).

那么就变成一道水题了,因为这是一个有向无环图,不存在所有点的出度都不为零的情况.

所以必然有1个及以上的点出度为零,如果有两个点出度为零,那么这两个点肯定是不相连的,即这两圈牛不是互相崇拜的,于是此时答案为零,如果有1个点出度为0,那么这个点就是被全体牛崇拜的.

这个点可能是一个强联通分量缩成的 超级点,所以应该输出整个强联通分量中点的个数.

— stxy-ferryman

/* 以上同 Tarjan 求强连通分量. */

int deg[N], cnt[N];
int tot=0, ans=0; for (int i=1; i<=n; ++i) {
for (int k=head[i]; k; k=nex[k]) if (col[to[k]]!=col[i]) ++deg[col[i]];
++cnt[col[i]];
}
for (int i=1; i<=ct; ++i) if (!deg[i]) ++tot, ans=cnt[i];
if (!tot || tot>1) printf("0\n"); else printf("%d\n", ans);

割点、桥

无向图.

割点

特判:根节点如果有两个及以上的儿子,那么他也是割点.

int dfn[N], low[N], t, root;
bool cut[N]; void tarjan(int x) {
int flag=0;
dfn[x]=low[x]=++t;
for (int k=head[x]; k; k=nex[k]) {
if (dfn[to[k]]) low[x]=min(low[x], dfn[to[k]]);
else {
tarjan(to[k]), low[x]=min(low[x], low[to[k]]);
if (low[y]>=dfn[x]) {
++flag;
if (x!=root || flag>1) cut[x]=true;
}
}
}
} for (int i=1; i<=n; ++i) if (!dfn[i]) tarjan(root=i);
for (int i=1; i<=n; ++i) if (cut[i]) printf("%d ", i);

桥

邻接表存图编号从2开始. 即开头 head[0]=1;.

int dfn[N], low[N], t;
bool bdg[N<<1]; void tarjan(int x, int last) {
dfn[x]=low[x]=++t;
for (int k=head[x]; k; k=nex[k]) {
if (dfn[to[k]]) if (i!=(last^1)) low[x]=min(low[x], dfn[to[k]]);
else {
tarjan(to[k], k), low[x]=min(low[x], low[to[k]]);
if (low[y]>=dfn[x]) bdg[k]=bdg[k^1]=true;
}
}
} for (int i=1; i<=n; ++i) if (!dfn[i]) tarjan(i, 0);
for (int i=2; i<head[0]; i+=2) if (bdg[i]) printf("%d %d\n", to[i^1], to[i]);

杂项

图论技巧

NOIp 图论算法专题总结 (2)的更多相关文章

  1. NOIp 图论算法专题总结 (1):最短路、最小生成树、最近公共祖先

    系列索引: NOIp 图论算法专题总结 (1) NOIp 图论算法专题总结 (2) NOIp 图论算法专题总结 (3) 最短路 Floyd 基本思路:枚举所有点与点的中点,如果从中点走最短,更新两点间 ...

  2. NOIp 图论算法专题总结 (3):网络流 & 二分图 简明讲义

    系列索引: NOIp 图论算法专题总结 (1) NOIp 图论算法专题总结 (2) NOIp 图论算法专题总结 (3) 网络流 概念 1 容量网络(capacity network)是一个有向图,图的 ...

  3. 算法专题 | 10行代码实现的最短路算法——Bellman-ford与SPFA

    今天是算法数据结构专题的第33篇文章,我们一起来聊聊最短路问题. 最短路问题也属于图论算法之一,解决的是在一张有向图当中点与点之间的最短距离问题.最短路算法有很多,比较常用的有bellman-ford ...

  4. 图论算法-最小费用最大流模板【EK;Dinic】

    图论算法-最小费用最大流模板[EK;Dinic] EK模板 const int inf=1000000000; int n,m,s,t; struct node{int v,w,c;}; vector ...

  5. 图论算法-网络最大流【EK;Dinic】

    图论算法-网络最大流模板[EK;Dinic] EK模板 每次找出增广后残量网络中的最小残量增加流量 const int inf=1e9; int n,m,s,t; struct node{int v, ...

  6. 图论算法-Tarjan模板 【缩点;割顶;双连通分量】

    图论算法-Tarjan模板 [缩点:割顶:双连通分量] 为小伙伴们总结的Tarjan三大算法 Tarjan缩点(求强连通分量) int n; int low[100010],dfn[100010]; ...

  7. NOIP基本算法

    NOIP基本算法 1.二分 poj 2018 Best Cow Fences ▪ http://poj.org/problem?id=2018 ▪ 题意:给定一个正整数数列

  8. [算法专题] LinkedList

    前段时间在看一本01年出的旧书<effective Tcp/Ip programming>,这个算法专题中断了几天,现在继续写下去. Introduction 对于单向链表(singly ...

  9. 【枚举Day1】20170529-2枚举算法专题练习 题目

    20170529-2枚举算法专题练习 题解: http://www.cnblogs.com/ljc20020730/p/6918360.html 青岛二中日期 序号 题目名称 输入文件名 输出文件名 ...

随机推荐

  1. JS中$含义及用法

    $在JS中本身只是一个符号而异,在JS里什么也不是.但在JS应用库JQUERY的作者将之做为一个自定义函数名了,这个函数是获取指定网页元素的函数,使用非常之频繁,所以好多新手不知道,还以为$是JS的什 ...

  2. HTML--JS 9*9乘法口诀

    <html> <head> <title>9*9乘法口诀</title> <script language="JavaScript&qu ...

  3. canvas绘制小人开口和闭口

    css: <style> body{ text-align: center; } canvas{ background: #ddd; } </style>canvas标签:&l ...

  4. 使用Atom写你的笔记

    使用Atom写你的笔记 本文参考简书笔记. 使用sync-settings同步你的Atom设置 使用sync-settings插件需要以下3个条件: 电脑已安装Atom Atom内已安装sync-se ...

  5. 求bit中1的个数有几种做法

    原文 求bit中1的个数有几种做法: - x & (x - 1) - Hamming weight的经典求法,基于树状累加:http://en.wikipedia.org/wiki/Hammi ...

  6. jsp(java server page)

    jsp的组成元素; 1, 指令 page指令 <%@ page ..........%> language---当前页面使用的语言:java import---当前页面引入的类库, 默认是 ...

  7. [Python3] 022 面向对象 第二弹

    目录 6. 面向对象的三大特性 6.1 封装 6.1.1 私有 private 6.1.2 受保护 protected 6.1.3 公开 public 6.2 继承 6.2.1 继承的概念与作用 6. ...

  8. Communications link failure mysql自动停止 连接拒绝 mysqld dead but sub。。。

    服务器环境中 JAVA 连接数据库 Communications link failure, Contection refused 网上很多这种情况,解决基本上是将127.0.0.1换成localho ...

  9. eclipse新建maven项目出错 pom.xml报错

    问题: 1.新建项目后会提示一个这样的错 maven-compiler-plugin:3.1:compile(1 errors) maven-compiler-plugin:3.1:testCompi ...

  10. 两数相加(java版本)

    (一).单链表实现 package com.lin.leetcode.addTwoNumbers; /** * Created by Yaooo on 2019/8/26. */ public cla ...