[题目链接]
https://codeforces.com/contest/1229/problem/C
[题解]
维护每个点的可达集合 , 每个点的贡献是 \(in_{u} \cdot out_{u}\) , 在更新时直接维护这个值即可。
这样为什么复杂度正确呢? 考虑势能分析。
将每个点的势能定义为其度数。 将度数不超过 \(\sqrt{N}\) 的点集称为 \(A\) 集 , 其余称为 \(B\) 集。 显然 \(|B| \leq \sqrt{N}\)。
如果操作的点在 \(A\) 集中 , 那么转移的势能不超过 \(\sqrt{N}\)。
如果操作的点在 \(B\) 集中 , 对 \(B\) 集转移的势能是 \(\sqrt{N}\) (\(|B| \leq \sqrt{N}\))。
而对 \(A\) 集转移的势能必然和 \(A\) 给 \(B\) 的势能同级。 总转移量不超过 \(N \sqrt{N}\)。
故时间复杂度 : \(O(N \sqrt{N})\)
[代码]
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MN = 1e6 + 5;
int N , M , deg[MN];
vector < int > g[MN];
inline LL get(int u) {
return (LL) (g[u].size()) * (deg[u] - g[u].size());
}
int main() {
scanf("%d%d" , &N , &M);
for (int i = 0; i < M; ++i) {
int v , u; scanf("%d%d" , &v , &u);
if (v > u) swap(v , u);
g[v].emplace_back(u); ++deg[u]; ++deg[v];
}
LL ANS = 0;
for (int i = 1; i <= N; ++i) ANS += get(i);
printf("%lld\n" , ANS);
int Q; scanf("%d" , &Q);
while (Q--) {
int v; scanf("%d" , &v);
while (!g[v].empty()) {
int u = g[v].back();
ANS -= get(u) + get(v);
g[v].pop_back(); g[u].emplace_back(v);
ANS += get(u) + get(v);
}
printf("%lld\n" , ANS);
}
return 0;
}