题解 最小生成树
\(x\leqslant 5\) 可以预处理出所有 \(2^5\) 种前 5 条边选/不选的最小生成树权值和
考虑链怎么做
发现可以线段树维护,需要维护 \(l, r\) 与 0 是否连通的每种情况的最小权值
这个是可以合并的
然后正解使用 kruskal 构造等效链
正确性:(补的题解记不清了)
大概是若某条虚边 \(x\) 不合法,若新加的 1 类边边权较小,则用不到这个边
若较大,则当前边较小,新加的边无影响
复杂度 \(O(n\log n)\)
点击查看代码
// ubsan: undefined
// accoders
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define N 300010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m, q;
pair<int, ll> sta[N];
pair<int, int> node[N];
vector<pair<int, ll>> to[N];
int a[N], dsu[N], pos[N], top;
struct edge{int fir, sec, val;}e[N];
inline bool operator < (edge a, edge b) {return a.val<b.val;}
inline int find(int p) {return dsu[p]==p?p:dsu[p]=find(dsu[p]);}
inline void chkmin(ll& a, ll b) {a=min(a, b);}
#define tl(p) tl[p]
#define tr(p) tr[p]
int tl[N<<2], tr[N<<2];
ll dat[N<<2][2][2], rval[N<<2];
inline void pushup(int p) {
for (int i=0; i<2; ++i)
for (int j=0; j<2; ++j)
dat[p][i][j]=min({dat[p<<1][i][1]+rval[p<<1]+dat[p<<1|1][0][j], dat[p<<1][i][0]+rval[p<<1]+dat[p<<1|1][1][j], dat[p<<1][i][1]+dat[p<<1|1][1][j]});
}
void build(int p, int l, int r) {
tl(p)=l; tr(p)=r;
if (l==r) {dat[p][1][1]=a[sta[l].fir]; rval[p]=sta[l].sec; return ;}
int mid=(l+r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
rval[p]=rval[p<<1|1];
pushup(p);
}
void upd(int p, int pos, int val) {
if (tl(p)==tr(p)) {dat[p][1][1]=val; return ;}
int mid=(tl(p)+tr(p))>>1;
if (pos<=mid) upd(p<<1, pos, val);
else upd(p<<1|1, pos, val);
pushup(p);
}
void dfs(int u, int fa) {
sta[++top]={u, INF};
for (auto& v:to[u]) if (v.fir!=fa)
sta[top].sec=v.sec, dfs(v.fir, u);
}
signed main()
{
freopen("mst.in", "r", stdin);
freopen("mst.out", "w", stdout);
n=read(); m=read();
for (int i=1; i<=n; ++i) a[i]=read();
for (int i=1,u,v,w; i<=m; ++i) {
u=read(); v=read(); w=read();
e[i]={u, v, w};
}
sort(e+1, e+m+1);
for (int i=1; i<=n; ++i) dsu[i]=i, node[i]={i, i};
for (int i=1,s,t; i<=m; ++i) if ((s=find(e[i].fir))!=(t=find(e[i].sec))) {
dsu[s]=t;
to[node[s].sec].pb({node[t].fir, e[i].val});
to[node[t].fir].pb({node[s].sec, e[i].val});
node[t].fir=node[s].fir;
}
for (int i=1; i<=n; ++i) if (find(i)==i) dfs(node[i].fir, 0);
assert(top==n);
// cout<<"sta: "; for (int i=1; i<=n; ++i) cout<<"("<<sta[i].fir<<','<<(sta[i].sec==INF?(ll)(0x3f3f3f3f):sta[i].sec)<<") "; cout<<endl;
for (int i=1; i<=n; ++i) pos[sta[i].fir]=i;
build(1, 1, n);
q=read();
while (q--) {
int x=read(), y=read();
upd(1, pos[x], y);
printf("%lld\n", dat[1][1][1]);
}
return 0;
}