hihoCoder #1161 八卦的小冰

题目大意

考虑一个由 \(n\) 个人构成的社交网络,其中任意两人都有一个用非负整数表示的亲密度。
初始时给出 \(m\) 对人的亲密度,其余的亲密度为 \(0\)
定义此社交网络的「八卦度」为异性之间的亲密度之和。
要求维护三种操作:

  1. 修改某人的性别
  2. 修改某两人的亲密度
  3. 询问八卦度

操作总数为 \(q\)
数据范围:
\(1 \le n, m, q \le 100000\)

解法

这个社交网络可用一个无向图表示,亲密度为边的权值,按边所连接的两个点(人)的性别将边分为「同性边」和「异性边」。

先考虑暴力做法:
修改性别或亲密度都需要遍历某个点或某两个点的临接边表,复杂度太高。
一个优化是,用 std::map<pair<int,int>,int> 维护边的权值(即亲密度);
即便如此,修改性别仍需要遍历点的邻接边表。

正解是:
将无向图改造成有向图,边的方向由「度数小的点」指「向度数大的点」。
\(c(u)\) 表示 \(u\) 的出边的数目。

对每个点 \(u\) 维护两个值 \(s_1\), \(s_2\),分别表示指向 \(u\) 的边中同性边的权值之和 和 异性边的权值之和。

这样,对于改变点 \(u\) 性别的操作,需要:

  1. 交换 \(s_1[u]\)\(s_2[u]\)
  2. \(u\) 的出边指向的点 \(v\),修改 \(s_1[v]\)\(s_2[v]\)

复杂度为 \(O(c(u))\)

对于修改亲密度的操作,首先找到对应的那条边 \((u,v)\),修改其权值,再更新 \(s_1[v]\)\(s_2[v]\)

复杂度为 \(O(c(u) + c(v))\)

下面证明 $c(u) = O(\sqrt{m}) \(,\)m$ 是边数。
证明:点 \(u\) 的出边指向的点的总度数为 \(\sum_{v\colon (u,v)\in E}\)

$2m > \sum_{v\colon (u,v)\in E} d(v) \ge c(u) d(u) \ge c(u)^2 \( 即 \)c(u) < \sqrt{2m}$
所以 \(c(u) = O(\sqrt{m})\)

上述证明里所考虑的图是静态的。对于这个题目,我们可以采用离线的方式,将动态图转化成静态图,但这样就增加了编程复杂度。
下面考虑在动态添边的情况下是否还有类似的结论。

为了便于描述,我们把 \(u\) 的出边所指向的点称作 \(u\) 的「出邻点」,将 \(u\) 的出邻点的集合记作 \(N^-(u)\),则 \(c(u) = |N^-(u)|\)
\(d(N^-(u)) = \sum_{v\in N^-(u)} d(v)\)

考虑往途中增加一条(有向)边 \((u,v)\) 之后的情形:
\(d(u) \to d(u)+1\)
\(d(N^-(u))\) 的增量 \(\Delta\) 满足
$\Delta \ge d(u) + 1 $

所以
\(2m > d(N^-(u)) \ge 1 + 2 + 3 + \dots + c(u)\)
同样有
\(c(u) = O(\sqrt{m})\)

posted @ 2017-12-26 11:37  Pat  阅读(321)  评论(0编辑  收藏  举报