题目大意:
给出n个点m条边,然后给出q个询问,表示把目前第numi条边的边权修改为di后的mst。
一个分治算法
两个重要的操作 Contraction 和 Reduction 操作。 详见论文《Offline Algorithms for Dynamic Minimum Spanning Tree Problems》
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define MAXT 50010
#define MAXM 100010
#define MAXN 50010
using namespace std;
const long long INF = 1LL <<40;
int n,m,q;
int x[MAXM],y[MAXM],num[MAXM],d[MAXM],f[MAXN],ord[MAXM],t[MAXN];
long long z[MAXM],c[MAXM], answer;
struct Edge{
int cnt;
int a[MAXM*5],b[MAXN*5];
inline void renew(int);
inline void merge(int u,int v);
inline int find(int v);
}edge[20];
inline void Edge::renew(int top = 0)
{
for (;cnt != top; --cnt)
f[a[cnt]] = b[cnt];
}
inline void Edge::merge(int v,int u)
{
int _v = find(v);
int _u = find(u);
a[++cnt] = _v;
b[cnt] = f[_v];
f[_v] = _u;
}
inline int Edge::find(int v)
{
if (!f[v]) return v;
int ret = v;
while (f[ret]) ret = f[ret];
while (f[v] != ret)
{
a[++cnt] = v;
b[cnt] = f[v];
f[v] = ret; v = b[cnt];
}
return ret;
}
void Qsort(int l,int r)
{
long long k = z[ord[(l+r)/2]];
int i = l, j = r;
while (i<j)
{
while (z[ord[i]] < k) i++;
while (z[ord[j]] > k) j--;
if (i<=j)
swap(ord[i++], ord[j--]);
}
if (i<r) Qsort(i,r);
if (l<j) Qsort(l,j);
}
inline void work(int l ,int r,int dep)
{
Edge &e = edge[dep];
e.cnt = 0;
if (l>r) return ;
if (l == r)
{
z[num[l]] = c[num[l]] = d[l];
Qsort(1,m);
long long ans = answer;
for (int i = 1; i <= m;++i)
if (e.find(x[ord[i]]) != e.find(y[ord[i]]))
{
ans+=z[ord[i]];
e.merge(x[ord[i]],y[ord[i]]);
}
e.renew();
printf("%lld\n",ans);
return ;
}
int temp_m = m;
long long temp_ans = answer;
//Contrresume;
for (int i = l; i <= r; ++i) z[num[i]] = -INF;
Qsort(1,m);
t[0] = 0;
for (int i = 1; i <= m; ++i)
{
if (e.find(x[ord[i]]) != e.find(y[ord[i]]))
{
if (z[ord[i]] != -INF) t[++t[0]] = ord[i];
e.merge(x[ord[i]],y[ord[i]]);
}
}
e.renew();
for (int i = 1; i <= t[0] ; ++i)
{
e.merge(x[t[i]], y[t[i]]);
answer +=z[t[i]];
}
int temp_cnt = e.cnt;
//Reduction
for (int i = l; i <= r; ++i) z[num[i]] = INF;
Qsort(1,m);
t[0] =0;
for (int i = 1; i <= m; ++i)
{
if (e.find(x[ord[i]]) != e.find(y[ord[i]]))
e.merge(x[ord[i]], y[ord[i]]);
else
{
if (z[ord[i]] != INF) t[++t[0]] = i;
}
}
for (int i = t[0]; i ; --i) swap(ord[t[i]],ord[m--]);
e.renew(temp_cnt);
for (int i =l ; i<=r; ++i) z[num[i]] = c[num[i]];
work(l,(l+r)/2, dep+1);
work((l+r)/2+1,r,dep+1);
e.renew();
answer = temp_ans;
m = temp_m;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= m ;++i)
{
scanf("%d %d %d", &x[i],&y[i],&z[i]);
c[i] = z[i];
ord[i] = i;
}
scanf("%d",&q);
Qsort(1,m);
for (int i = 1; i <= q; ++i)
scanf("%d %d", &num[i], &d[i]);
work(1,q,0);
return 0;
}