【BZOJ2594】【WC2006】水管局长数据加强版

【题目链接】

【思路要点】

  • 若题目仅包含询问操作,显然我们只需保留一棵图的最小生成树,在树上询问两点间边权的最大值即可。
  • 而本题中多了一种删边操作,但没有强制在线,因此,我们可以将操作离线,转化为加边操作。
  • 用LinkCutTree维护动态最小生成树即可。
  • 时间复杂度\(O((M+Q)LogN)\)。

【代码】

#include<bits/stdc++.h>
using namespace std;
#define MAXN	300005
#define MAXM	1000005
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
struct LinkCutTree {
	struct Node {
		int child[2], father, up;
		int index, Max, home;
		bool rev;
	} a[MAXN];
	int size;
	int hx[MAXN], hy[MAXN];
	void pushdown(int root) {
		if (a[root].rev == false) return;
		swap(a[root].child[0], a[root].child[1]);
		if (a[root].child[0]) a[a[root].child[0]].rev ^= true;
		if (a[root].child[1]) a[a[root].child[1]].rev ^= true;
		a[root].rev = false;
	}
	bool get(int x) {
		return x == a[a[x].father].child[1];
	}
	void update(int root) {
		a[root].Max = a[root].index;
		a[root].home = root;
		if (a[root].child[0]) {
			int tmp = a[root].child[0];
			if (a[tmp].Max > a[root].Max) {
				a[root].Max = a[tmp].Max;
				a[root].home = a[tmp].home;
			}
		}
		if (a[root].child[1]) {
			int tmp = a[root].child[1];
			if (a[tmp].Max > a[root].Max) {
				a[root].Max = a[tmp].Max;
				a[root].home = a[tmp].home;
			}
		}
	}
	void rotate(int x) {
		if (a[x].father == 0) return;
		pushdown(a[x].father);
		pushdown(x);
		int f = a[x].father, g = a[f].father;
		bool tmp = get(x), tnp = get(f);
		a[x].up = a[f].up;
		a[f].up = 0;
		a[f].child[tmp] = a[x].child[tmp ^ 1];
		a[a[x].child[tmp ^ 1]].father = f;
		a[f].father = x;
		a[x].child[tmp ^ 1] = f;
		a[x].father = g;
		a[g].child[tnp] = x;
		update(f);
		update(x);
	}
	void splay(int x) {
		pushdown(x);
		for (int f = a[x].father; (f = a[x].father); rotate(x))
			if ((f = a[x].father)) {
				if (get(f) == get(x)) rotate(f);
				else rotate(x);
			}
	}
	void access(int x) {
		splay(x);
		int tmp = a[x].child[1];
		a[x].child[1] = 0;
		update(x);
		a[tmp].father = 0;
		a[tmp].up = x;
		while (a[x].up) {
			int f = a[x].up;
			splay(f);
			tmp = a[f].child[1];
			a[f].child[1] = x;
			update(f);
			a[tmp].father = 0;
			a[tmp].up = f;
			a[x].father = f;
			a[x].up = 0;
			splay(x);
		}
	}
	void reverse(int x) {
		access(x);
		splay(x);
		a[x].rev ^= true;
	}
	void init(int n) {
		size = n;
	}
	void link(int x, int y) {
		access(x);
		splay(x);
		reverse(y);
		access(y);
		a[x].child[1] = y;
		a[y].father = x;
		update(x);
	}
	void link(int x, int y, int z) {
		size++;
		hx[size] = x;
		hy[size] = y;
		a[size].Max = a[size].index = z;
		a[size].home = size;
		link(x, size);
		link(y, size);
	}
	int query(int x, int y) {
		reverse(x);
		access(y);
		splay(y);
		return a[y].Max;
	}
	void cut(int x, int y) {
		reverse(x);
		access(y);
		splay(x);
		a[x].child[1] = 0;
		a[y].father = 0;
		update(x);
	}
	void cut(int x) {
		cut(x, hx[x]);
		cut(x, hy[x]);
	}
	void addedge(int x, int y, int z) {
		reverse(x);
		access(y);
		splay(y);
		if (a[y].Max <= z) return;
		cut(a[y].home);
		link(x, y, z);
	}
} LCT;
struct edge {int x, y, len; };
int n, m, q;
int f[MAXN], k[MAXN];
int x[MAXN], y[MAXN], z[MAXN];
bool disable[MAXM];
edge a[MAXM];
map <int, int> home[MAXN];
vector <int> ans;
int F(int x) {
	if (f[x] == x) return x;
	else return f[x] = F(f[x]);
}
bool cmp(edge a, edge b) {
	return a.len < b.len;
}
int main() {
	read(n), read(m), read(q);
	for (int i = 1; i <= m; i++)
		read(a[i].x), read(a[i].y), read(a[i].len);
	sort(a + 1, a + m + 1, cmp);
	for (int i = 1; i <= m; i++) {
		if (a[i].x > a[i].y) swap(a[i].x, a[i].y);
		home[a[i].x][a[i].y] = i;
	}
	for (int i = 1; i <= q; i++) {
		read(k[i]), read(x[i]), read(y[i]);
		if (k[i] == 2) {
			if (x[i] > y[i]) swap(x[i], y[i]);
			int tmp = home[x[i]][y[i]];
			disable[tmp] = true;
			z[i] = a[tmp].len;
		}
	}
	LCT.init(n);
	for (int i = 1; i <= n; i++)
		f[i] = i;
	for (int i = 1; i <= m; i++) {
		if (disable[i]) continue;
		int rx = F(a[i].x), ry = F(a[i].y);
		if (rx == ry) continue;
		f[rx] = ry;
		LCT.link(a[i].x, a[i].y, a[i].len);
	}
	for (int i = q; i >= 1; i--) {
		if (k[i] == 1) ans.push_back(LCT.query(x[i], y[i]));
		else LCT.addedge(x[i], y[i], z[i]);
	}
	reverse(ans.begin(), ans.end());
	for (unsigned i = 0; i < ans.size(); i++)
		printf("%d\n", ans[i]);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值