「BZOJ2594」[Wc2006] 水管局长数据加强版

可以先做普通版本 \(->\) 水管局长

Description

给一个n个点m条边的图,支持以下操作:

  • 询问 \(x\)\(y\) 所有路径中,路径上最大边权的最小值;
  • 删去一条边;

Solution

基本思路和普通版本差不多。

因为删边操作较难实现,我们选择反其道而行之,进行加边操作。

边的处理

  • 先将所有的边用结构体储存,因为数据加强,用数组储存编号自然是不现实的。只能采用搜索。所以为了方便查找,输入时要处理好两个节点的大小关系;
  • 将边先按照长度排序,方便后面将边转化成点的操作;
  • 然后再输入断边的时候查找当前边的编号,做一个标记;
  • 前面处理完后,将未被标记(没有断)的边连上,预处理。
  • 最后因为是反过来加边,所以倒叙处理。

小技巧边转化成点

其实就是把边看做一个点,分别连向两个端点。

也就是,一条边 \((x\) \(--\) \(y)\) \(==>\) \((x\) \(--\) \(z\) \(--\) \(y)\)

所以问题就转化为了动态维护最小生成树

因为是一颗生成树,所以每次加边必定会构成一个环。又因为我们维护的是最小生成树,所以要将这个环里最大的一条边删去。也就是在没有加边时两个端点之间的最大边权和新加边权进行比较,删去最大的一条。

后面的加边操作

加上 \((u,v)\) 这条边。

  • 查找 \(u\)\(v\) 这条链上的最大边权;
  • 如果新边权更大不作任何操作;
  • 否则删去原来的边,加上新边。

查询答案

在修改的时候已经维护了最大值,所以直接查询链上的最大值即可。

后面就是常规操作了,注意边转化成点后的编号为 \(n + i\) 哦~

Code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1500005;
#define il inline
#define ls ch[x][0]
#define rs ch[x][1]
il int read() {
	int x = 0; char s = getchar();
	while(s < '0' || s > '9') s = getchar();
	while(s <= '9' && s >= '0') x = x * 10 + s - '0', s = getchar();
	return x;  
}
bool tag[N];
int m,top,tot,fa[N],mx[N],val[N],ch[N][2],sta[N],fb[N];
struct node {int u,v,w,id; bool d;}e[N];
struct Query {int f,x,y,ans,id;}q[N];
il bool operator<(node a,node b) {
	return a.u < b.u || (a.u == b.u && a.v < b.v);
}
il bool cmp(node a,node b) {return a.w < b.w;}
il bool cmp2(node a,node b) {return a.id < b.id;}
il int getfa(int x) {return x == fb[x] ? x : fb[x] = getfa(fb[x]);}
il int find(int x,int y) {
	int l = 1, r = m, mid;
	while(l <= r) {
		mid = (l + r) >> 1;
		if(e[mid].u < x || (e[mid].u == x && e[mid].v < y)) l = mid + 1;
		else if(e[mid].u == x && e[mid].v == y) return mid;
		else r = mid - 1;
	}
}
il bool check(int x) {
	return ch[fa[x]][0] != x && ch[fa[x]][1] != x; 
}
il void update(int x) {
	mx[x] = x;
	if(val[mx[ls]] > val[x]) mx[x] = mx[ls];
	if(val[mx[rs]] > val[mx[x]]) mx[x] = mx[rs]; 
}
il int ident(int x) {
	return ch[fa[x]][1] == x;
}
il void rotate(int x) {
	int f = fa[x], ff = fa[f], k = ident(x);
	if(!check(f)) ch[ff][ident(f)] = x;
	fa[x] = ff, fa[f] = x, fa[ch[x][k ^ 1]] = f;
	ch[f][k] = ch[x][k ^ 1], ch[x][k ^ 1] = f;
	update(f), update(x);
}
il void pushdown(int x) {
	if(tag[x]) {
		tag[x] = 0, tag[ls] ^= 1, tag[rs] ^= 1;
		swap(ls,rs);
	}
}
il void splay(int x) {
	sta[top = 1] = x;
	int y = x, f, ff;
	while(!check(y)) sta[++top] = fa[y], y = fa[y];
	while(top) pushdown(sta[top--]);
	while(!check(x)) {
		f = fa[x];
		if(!check(f)) ident(x) ^ ident(f) ? rotate(x) : rotate(f);
		rotate(x);
	}
}
il void access(int x) {
	for(register int y = 0; x; x = fa[y = x]) {
		splay(x), rs = y, update(x);
	}
}
il void makert(int x) {
	access(x), splay(x), tag[x] ^= 1;
}
il void link(int x,int y) {
	makert(x), fa[x] = y;
}
il void cut(int x,int y) {
	makert(x), access(y), splay(y);
	fa[x] = ch[y][0] = 0;
}
il int query(int x,int y) {
	makert(x), access(y), splay(y);
	return mx[y];
}
int main() {
	int i,n,qq,u,v,x,y,k,t;
	n = read(), m = read(), qq = read();
	for(i = 1; i <= n; i ++) fb[i] = i;
	for(i = 1; i <= m; i ++) {
		e[i].u = read(), e[i].v = read(), e[i].w = read();
		if(e[i].u > e[i].v) swap(e[i].u, e[i].v);
	}
	sort(e + 1, e + 1 + m, cmp);
	for(i = 1; i <= m; i ++) {
		e[i].id = i, val[n + i] = e[i].w, mx[n + i] = n + i;
	}
	sort(e + 1,e + m + 1);
	for(i = 1; i <= qq; i ++) {
		q[i].f = read(), q[i].x = read(), q[i].y = read();
		if(q[i].f == 2) {
			if(q[i].x > q[i].y) swap(q[i].x,q[i].y);
			int t = find(q[i].x,q[i].y);
			e[t].d = 1, q[i].id = e[t].id;
		}
	}
	sort(e + 1,e + 1 + m,cmp2);
	for(i = 1; i <= m; i ++) {
		if(!e[i].d) {
			u = e[i].u, v = e[i].v, x = getfa(u), y = getfa(v);
			if(x != y) {
				fb[x] = y;
				link(u,i + n), link(v,i + n), tot++;
				if(tot == n - 1) break;
			}
		}
	}
	for(i = qq; i; i --) {
		if(q[i].f == 1) q[i].ans = val[query(q[i].x,q[i].y)];
		else {
			u = q[i].x, v = q[i].y, k = q[i].id, t = query(u,v);
			if(e[k].w < val[t]) {
				cut(e[t - n].u,t), cut(e[t - n].v,t);
				link(u,k + n), link(v,k +n);
			}
		}
	}
	for(i = 1; i <= qq; i ++) {
		if(q[i].f == 1) printf("%d\n",q[i].ans);
	}
	return 0;
}

posted @ 2021-02-24 11:48  Spring-Araki  阅读(65)  评论(0)    收藏  举报