「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;
}

浙公网安备 33010602011771号