hihoCoder #1161 八卦的小冰
题目大意
考虑一个由 \(n\) 个人构成的社交网络,其中任意两人都有一个用非负整数表示的亲密度。
初始时给出 \(m\) 对人的亲密度,其余的亲密度为 \(0\) 。
定义此社交网络的「八卦度」为异性之间的亲密度之和。
要求维护三种操作:
- 修改某人的性别
- 修改某两人的亲密度
- 询问八卦度
操作总数为 \(q\) 。
数据范围:
\(1 \le n, m, q \le 100000\)
解法
这个社交网络可用一个无向图表示,亲密度为边的权值,按边所连接的两个点(人)的性别将边分为「同性边」和「异性边」。
先考虑暴力做法:
修改性别或亲密度都需要遍历某个点或某两个点的临接边表,复杂度太高。
一个优化是,用 std::map<pair<int,int>,int>
维护边的权值(即亲密度);
即便如此,修改性别仍需要遍历点的邻接边表。
正解是:
将无向图改造成有向图,边的方向由「度数小的点」指「向度数大的点」。
用 \(c(u)\) 表示 \(u\) 的出边的数目。
对每个点 \(u\) 维护两个值 \(s_1\), \(s_2\),分别表示指向 \(u\) 的边中同性边的权值之和 和 异性边的权值之和。
这样,对于改变点 \(u\) 性别的操作,需要:
- 交换 \(s_1[u]\) 和 \(s_2[u]\) 。
- 对 \(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})\)