\(\mathcal{Description}\)

  Link.

  给定一个 \(n\) 个点 \(m\) 条边的连通无向图,并给出 \(q\) 个点对 \((u,v)\),令 \(u\) 到 \(v\) 的路径所必经的结点权值 \(+1\)。求最终每个结点的权值。

  \(n\le10^5\),\(m,q\le2\times10^5\)。

\(\mathcal{Solution}\)

  看到”必经之点“,应该考虑圆方树。

  对于每个点对,直接在圆方树上作差分。具体地,两个圆点的 tag++,其 LCA 和 LCA 的父亲(如果存在)的 tag--,最后一遍 DFS 求每个圆点的子树 tag 和即可。

  复杂度 \(\mathcal O(n)\)。

\(\mathcal{Code}\)

#include <cstdio>

const int MAXN = 1e5, MAXM = 2e5;
int n, m, q, snode;
int dfc, top, dfn[MAXN + 5], low[MAXN + 5], stk[MAXN + 5];
int dep[MAXN * 2 + 5], fa[MAXN * 2 + 5][20], tag[MAXN * 2 + 5], sum[MAXN * 2 + 5]; struct Graph {
int ecnt, head[MAXN * 2 + 5], to[MAXM * 2 + 5], nxt[MAXM * 2 + 5];
inline void link ( const int s, const int t ) {
to[++ ecnt] = t, nxt[ecnt] = head[s];
head[s] = ecnt;
}
inline void add ( const int u, const int v ) {
link ( u, v ), link ( v, u );
}
} src, tre; inline bool chkmin ( int& a, const int b ) { return b < a ? a = b, true : false; } inline void Tarjan ( const int u, const int f ) {
dfn[u] = low[u] = ++ dfc, stk[++ top] = u;
for ( int i = src.head[u], v; i; i = src.nxt[i] ) {
if ( ( v = src.to[i] ) == f ) continue;
if ( ! dfn[v] ) {
Tarjan ( v, u ), chkmin ( low[u], low[v] );
if ( low[v] >= dfn[u] ) {
tre.add ( u, ++ snode );
do tre.add ( snode, stk[top] ); while ( stk[top --] ^ v );
}
} else chkmin ( low[u], dfn[v] );
}
} inline void init ( const int u, const int f ) {
dep[u] = dep[fa[u][0] = f] + 1;
for ( int i = 1; i <= 17; ++ i ) fa[u][i] = fa[fa[u][i - 1]][i - 1];
for ( int i = tre.head[u], v; i; i = tre.nxt[i] ) {
if ( ( v = tre.to[i] ) ^ f ) {
init ( v, u );
}
}
} inline int calcLCA ( int u, int v ) {
if ( dep[u] < dep[v] ) u ^= v ^= u ^= v;
for ( int i = 17; ~ i; -- i ) if ( dep[fa[u][i]] >= dep[v] ) u = fa[u][i];
if ( u == v ) return u;
for ( int i = 17; ~ i; -- i ) if ( fa[u][i] ^ fa[v][i] ) u = fa[u][i], v = fa[v][i];
return fa[u][0];
} inline void calcAns ( const int u, const int f ) {
sum[u] = tag[u];
for ( int i = tre.head[u], v; i; i = tre.nxt[i] ) {
if ( ( v = tre.to[i] ) ^ f ) {
calcAns ( v, u ), sum[u] += sum[v];
}
}
} int main () {
scanf ( "%d %d %d", &n, &m, &q ), snode = n;
for ( int i = 1, u, v; i <= m; ++ i ) {
scanf ( "%d %d", &u, &v );
src.add ( u, v );
}
Tarjan ( 1, 0 ), init ( 1, 0 );
for ( int i = 1, u, v; i <= q; ++ i ) {
scanf ( "%d %d", &u, &v );
++ tag[u], ++ tag[v];
int w = calcLCA ( u, v );
-- tag[w];
if ( fa[w] ) -- tag[fa[w][0]];
}
calcAns ( 1, 0 );
for ( int i = 1; i <= n; ++ i ) printf ( "%d\n", sum[i] );
return 0;
}

最新文章

  1. 利用浏览器LocalStorage缓存图片,视频文件
  2. The Practical Guide to Empathy Maps: 10-Minute User Personas
  3. asp.net &lt;asp:Content&gt;控件
  4. C# 基础(8)--网络编程
  5. 修改win7登录界面
  6. 对于fmri的设计矩阵构造的一个很直观的解释-by 西南大学xulei教授
  7. javascript数字转汉字中文数字
  8. 批处理DataTable
  9. Android_Handler
  10. Linux中find、grep命令详细用法
  11. Angular2 - Starter - Component and Component Lifecircle Hooks
  12. Makefile学习(二)条件判断和内嵌函数
  13. 【D3.V3.js系列教程】--(十五)SVG基本图形绘制
  14. python+selenium自动测试之WebDriver的常用API(基础篇一)
  15. 2018-2019 20165235 网络对抗 Exp5 MSF基础
  16. 将python中的一个float变量转成内存的4个字节值
  17. 51Nod - 1046 (附关于快速幂的讨论)
  18. iOS 10的两个坑
  19. Django的学习进阶(二)———— name
  20. 键值对的算子讲解 PairRDDFunctions

热门文章

  1. vs2017 winform 组件 -- 总结
  2. 深入谈谈 Java IOC 和 DI
  3. yii2安装配置完成后,网页打开报错yii\web\Request::cookieValidationKey must be configured with a secret key
  4. spring boot 启动读取的配置文件优先级
  5. SYCOJ1793
  6. Flowable实战(四)BPMN2.0 启动与结束事件
  7. 关于Jmeter线程数Ramp-Up.循环次数的理解和实验数据
  8. 《剑指offer》面试题16. 数值的整数次方
  9. [Altium Designer 学习]怎样输出Gerber文件和钻孔文件
  10. 嵌入式硬件之ADC/DAC