题解 最小生成树

传送门

\(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;
}
posted @ 2022-07-23 21:29  Administrator-09  阅读(2)  评论(0编辑  收藏  举报