描述
给出有n个点, m条边的无向图, 每次修改一条边的权值, 求修改后的最小生成树的大小. 修改次数 ≤ 50000.
分析
- 还是CDQ分治, 但是有点特殊. 目前的CDQ分治还是停留在看题解看别人代码才理解的层面.
- 有一些边一定在部分修改后的最小生成树中, 这是优化的中心思想吧.
- 然后一个减少边的操作, 一个减少点的操作. 看课件吧.
- 减少点的方法是缩点, 用并查集.
- 一开始想用全局变量d, n, m, ans代替函数参数传递. 后来发现因为分治的缘故这样做是不行的.
代码
#include
#include
using namespace std;
typedef long long int lli;
const int maxd = 20;
const int maxn = 50000 + 10;
const int INF = 0x3f3f3f3f;
struct Node {
int x, y, w, k, id;
void init(int i) {
id = i;
scanf("%d %d %d", &x, &y, &w);
}
bool operator < (const Node& rhs) const {
return w < rhs.w;
}
}A[maxd][maxn];
struct Modify {
int k, d;
void init() {
scanf("%d %d", &k, &d);
}
}B[maxn];
struct UnionFindSet {
int pa[maxn];
void init(int n) {
for(int i = 1; i <= n; i++) pa[i] = i;
}
int find(int x) {
return x == pa[x] ? x : (pa[x] = find(pa[x]));
}
} ufs;
struct CDQ {
int pa[maxn], dis[maxn], pos[maxn];
void init(int m) {
for(int i = 1; i <= m; i++)
dis[A[0][i].id] = A[0][i].w;
}
// cur depth : d
// modify sequence : [L, R]
// points : n, edges : m
void solve(int d, int L, int R, int n, int m, lli ans=0LL) {
for(int i = 1; i <= m; i++) {
Node &a = A[d][i], &a2 = A[d-1][i];
a = (Node) {a2.x, a2.y, dis[a2.id], 0, a2.id};
pos[a.id] = i;
}
if(L == R) {
Modify& b = B[L];
A[d][pos[b.k]].w = dis[b.k] = b.d;
ufs.init(n);
sort(A[d]+1, A[d]+m+1);
for(int i = 1; i <= m; i++) {
Node& a = A[d][i];
int x = ufs.find(a.x), y = ufs.find(a.y);
if(x != y) {
ufs.pa[y] = x;
ans = ans + a.w;
}
}
printf("%lld\n", ans);
return;
}
// reduction
for(int i = L; i <= R; i++) A[d][pos[B[i].k]].k = 1; // tag of in {S}
ufs.init(n);
sort(A[d]+1, A[d]+m+1);
for(int i = 1; i <= m; i++) if(A[d][i].k == 0) {
Node& a = A[d][i];
int x = ufs.find(a.x), y = ufs.find(a.y);
if(x != y) {
ufs.pa[y] = x;
a.k = 2; // tag of in {T}
}
}
// contraction
for(int i = 1; i <= m; i++)
if(A[d][i].k == 1) A[d][i].w = -INF;
ufs.init(n);
sort(A[d]+1, A[d]+m+1);
for(int i = 1; i <= m; i++) if(A[d][i].k != 0) {
Node& a = A[d][i];
int x = ufs.find(a.x), y = ufs.find(a.y);
if(x != y) {
ufs.pa[y] = x;
if(a.k != 1) a.k = 3; // tag of in {T'-S}
}
}
// rebuild
ufs.init(n);
for(int i = 1; i <= m; i++) if(A[d][i].k == 3) {
Node& a = A[d][i];
int x = ufs.find(a.x), y = ufs.find(a.y);
ufs.pa[y] = x;
ans = ans + a.w;
}
int newn = 0, newm = 0;
for(int i = 1; i <= n; i++) pa[i] = 0;
for(int i = 1; i <= n; i++) {
int x = ufs.find(i);
if(!pa[x]) pa[x] = ++newn;
}
for(int i = 1; i <= m; i++) if(A[d][i].k != 0) {
Node& a = A[d][i];
int x = ufs.find(a.x), y = ufs.find(a.y);
if(x != y) A[d][++newm] = (Node) {pa[x], pa[y], a.w, a.k, a.id};
}
int M = (L+R) >> 1;
solve(d+1, L, M, newn, newm, ans);
solve(d+1, M+1, R, newn, newm, ans);
}
} cdq;
int main()
{
int n, m, q;
scanf("%d %d %d", &n, &m, &q);
for(int i = 1; i <= m; i++) A[0][i].init(i);
for(int i = 1; i <= q; i++) B[i].init();
cdq.init(m);
cdq.solve(1, 1, q, n, m);
return 0;
}