Solution -「BZOJ 3331」压力
2024-08-30 00:26:18
\(\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;
}
最新文章
- 利用浏览器LocalStorage缓存图片,视频文件
- The Practical Guide to Empathy Maps: 10-Minute User Personas
- asp.net <;asp:Content>;控件
- C# 基础(8)--网络编程
- 修改win7登录界面
- 对于fmri的设计矩阵构造的一个很直观的解释-by 西南大学xulei教授
- javascript数字转汉字中文数字
- 批处理DataTable
- Android_Handler
- Linux中find、grep命令详细用法
- Angular2 - Starter - Component and Component Lifecircle Hooks
- Makefile学习(二)条件判断和内嵌函数
- 【D3.V3.js系列教程】--(十五)SVG基本图形绘制
- python+selenium自动测试之WebDriver的常用API(基础篇一)
- 2018-2019 20165235 网络对抗 Exp5 MSF基础
- 将python中的一个float变量转成内存的4个字节值
- 51Nod - 1046 (附关于快速幂的讨论)
- iOS 10的两个坑
- Django的学习进阶(二)———— name
- 键值对的算子讲解 PairRDDFunctions
热门文章
- vs2017 winform 组件 -- 总结
- 深入谈谈 Java IOC 和 DI
- yii2安装配置完成后,网页打开报错yii\web\Request::cookieValidationKey must be configured with a secret key
- spring boot 启动读取的配置文件优先级
- SYCOJ1793
- Flowable实战(四)BPMN2.0 启动与结束事件
- 关于Jmeter线程数Ramp-Up.循环次数的理解和实验数据
- 《剑指offer》面试题16. 数值的整数次方
- [Altium Designer 学习]怎样输出Gerber文件和钻孔文件
- 嵌入式硬件之ADC/DAC