求调 / 求原
  • 板块学术版
  • 楼主_RainCappuccino_
  • 当前回复4
  • 已保存回复4
  • 发布时间2024/12/14 13:48
  • 上次更新2024/12/14 16:34:48
查看原帖
求调 / 求原
857626
_RainCappuccino_楼主2024/12/14 13:48

题意:给定一个图,和 qq 次查询,每次询问一条边,回答要使得这条边一定出现在任意最小生成树时它的权值最大可以修改到多少?

思路: 如果该边不在 MST 上,MST 上 uu to vv 的路径上的最大边权 - 1 即为它可以修改的最大边权 如果在,

  1. 一定在 MST 上,什么情况?割边,无可替代
  2. 不一定在 MST 上,那么值不变,显然有一条边可以替换这条边,求出可以替代这条边的所有非数边的权值最小值 - 1,相当于区间覆盖-> 树上倍增
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
const int N = 5e5 + 10;
const int M = 2e6 + 10;
typedef long long ll;
typedef pair<int, int> pi;
int n, m;
struct edge {
	int u, v, w, id;
	bool operator < (edge x) const {
		return w < x.w;
	}
}e[M];
vector<edge> g[N], g2[N];
struct dsu {
	int f[N], val[N];
	void init () {
		for (int i = 1; i <= n; i ++) f[i] = i;
	}
	int find (int x) {
		return f[x] = (f[x] == x ? x : find(f[x]));
	}
}d;
int son[N], dep[N], fath[N], dfn[N], top[N], siz[N], tmp, to[N], val[N];
int bel[N];
int fa[N][40], k;
void dfs1 (int u, int _fa) {
	siz[u] = 1, fath[u] = _fa, dep[u] = dep[_fa] + 1;
	fa[u][0] = _fa;
	for (int i = 1; ; i ++) {
		fa[u][i] = fa[fa[u][i - 1]][i - 1];
		if(!fa[u][i]) {
			k = max(k, i - 1);
			break;
		}
	}
	for (auto e : g[u]) {
		int v = e.v;
		if (v == _fa) continue;
		val[v] = e.w, bel[e.id] = v;
		dfs1 (v, u);
		if (siz[v] > siz[son[u]]) son[u] = v;
		siz[u] += siz[v];
	}
}
int mi[N][40];
void modify (int u, int v, int val) {
	if(dep[u] < dep[v]) swap(u, v);
	for (int i = k; i >= 0; i --) {
		if(dep[fa[u][i]] >= dep[v]) {
			mi[u][i] = val;
			u = fa[u][i];
		}
	}
	if(u == v) return;
	for (int i = k; i >= 0; i --) {
		if(fa[u][i] != fa[v][i]) {
			mi[u][i] = mi[v][i] = val;
			u = fa[u][i], v = fa[v][i];
		}
	}
}
void pushdown () {
	for (int i = k; i >= 1; i --) {
		for (int j = 1; j <= n; j ++) {
			if (!mi[j][i]) continue;
//			cout << j << ' ' << i << ' ' << mi[j][i] << endl;
			mi[j][i - 1] = min(mi[j][i - 1], mi[j][i]);
//			cout << mi[j][i - 1] << endl;
			mi[fa[j][i - 1]][i - 1] = min(mi[fa[j][i - 1]][i - 1], mi[j][i]);
		}
	}
}
void dfs2 (int u, int tp) {
	top[u] = tp, dfn[u] = ++ tmp, to[tmp] = u;
	if(son[u]) dfs2(son[u], tp);
	for (auto e : g[u]) {
		if (e.v == fath[u] || e.v == son[u]) continue;
		dfs2 (e.v, e.v);
	}
}
struct tree {
	int ma[N][40];
#define mid (l + r >> 1)
#define ls p << 1, l, mid
#define rs (p << 1) | 1, mid + 1, r
	void build() {
		for (int i = 1; i <= n; i ++) ma[i][0] = val[to[i]];
		for (int k = 1; (1 << k) <= n; k ++) {
			for (int i = 1; i + (1 << k) - 1 <= n; i ++) {
				ma[i][k] = max(ma[i][k - 1], ma[i + (1 << k - 1)][k - 1]);
			}
		}
	}
	int getmax (int ql, int qr) {
		int len = log2(qr - ql + 1);
		return max (ma[ql][len], ma[qr - (1 << len) + 1][len]);
	}
}t;
int getmax (int u, int v) {
	int res = 0;
	while(top[u] != top[v]) {
		if(dep[top[u]] < dep[top[v]]) swap(u, v);
		int tmp = t.getmax(dfn[top[u]], dfn[u]);
		res = max(tmp, res);
		u = fath[top[u]];
	}
	if(dep[u] < dep[v]) swap(u, v);
	if (u == v) return res;
	int tmp = t.getmax(dfn[v] + 1, dfn[u]);
	res = max(res, tmp);
	return res;
}
int dfth[N], low[N], idx;
bool mark[M], mk[M];
void tarjan (int u, int from) {
	dfth[u] = low[u] = ++ idx;
	for (auto e : g2[u]) {
		int v = e.v;
		if (!dfth[v]) {
			tarjan(v, u);
			low[u] = min(low[u], low[v]);
			if (low[v] > dfth[u]) mark[e.id] = 1;
		} else if (v != from) low[u] = min(low[u], dfn[v]);
	}
}

signed main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= n; i ++) d.f[i] = i;
	for (int i = 1; i <= m; i ++) cin >> e[i].u >> e[i].v >> e[i].w, e[i].id = i;
	sort (e + 1, e + 1 + m);
	for (int i = 1; i <= m; i ++) {
		int u = e[i].u, v = e[i].v;
		if (d.find(u) != d.find(v)) {
			d.f[d.find(u)] = d.find(v);
			mk[e[i].id] = 1;
			g[u].push_back({u, v, e[i].w, e[i].id});
			g[v].push_back({v, u, e[i].w, e[i].id});
		}
		g2[u].push_back({u, v, e[i].w, e[i].id});
		g2[v].push_back({v, u, e[i].w, e[i].id});
	}
	dfs1 (1, 0);
	dfs2 (1, 1);
	for (int i = 1; i <= n; i ++)
		for (int j = 0; j <= k; j ++) mi[i][j] = 0x3f3f3f3f;
	t.build();
	for (int i = m; i >= 1; i --) {
		if (!mk[e[i].id]) modify(e[i].u, e[i].v, e[i].w);
	}
	pushdown();
	tarjan(1, 0);
	int q;
	sort (e + 1, e + 1 + m, [] (edge x, edge y) {
		return x.id < y.id;
	});
	cin >> q;
	while (q --) {
		int id;
		cin >> id;
		if (mark[id]) cout << -1 << endl;
		else {
			if (mk[id]) {
				int u = (dep[e[id].u] < dep[e[id].v] ? e[id].v : e[id].u);
				int v = mi[u][0];
				cout << v - 1 << endl;
			} else {
				cout << getmax(e[id].u, e[id].v) - 1 << endl;
			}
		}
	}
	return 0;
}
2024/12/14 13:48
加载中...