「WC2006」水管局长 - LCT

给定一个nn个点mm条边的图,有qq次操作:

  1. 询问xxyy所有路径中,路径上最大边权的最小值
  2. 删去一条边

n1000m,q105n\le 1000 ~ m,q\le10^5

Luogu P4172

Solution

把询问倒过来就变成LCT维护最小生成树模板题,做法见这篇blog

但是还是有很多细节写错。。。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#include <bits/stdc++.h>

#define x first
#define y second
#define y1 Y1
#define y2 Y2
#define mp make_pair
#define pb push_back

using namespace std;

typedef long long LL;
typedef pair<int, int> pii;

template <typename T> inline int Chkmax (T &a, T b) { return a < b ? a = b, 1 : 0; }
template <typename T> inline int Chkmin (T &a, T b) { return a > b ? a = b, 1 : 0; }

inline void proc_status()
{
ifstream t ("/proc/self/status");
cerr << string (istreambuf_iterator <char> (t), istreambuf_iterator <char> ()) <<endl;
}

template <typename T> T read ()
{
T sum = 0, fl = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fl = -1;
for (; isdigit(ch); ch = getchar()) sum = (sum << 3) + (sum << 1) + ch - '0';
return sum * fl;
}

const int Maxn = 1000 + 100, Maxm = 100000 + 100;

int N, M, Q;
vector <int> Ans;

struct node
{
int x, y, z, op;
}Edge[Maxm], Query[Maxm];
map <pii, int> S;

struct tree
{
int fa, ch[2], rev, max, val;
}Tree[Maxm << 3];

namespace LCT
{
#define ls (Tree[x].ch[0])
#define rs (Tree[x].ch[1])
int Stack[Maxm], top;

inline int is_root (int x) { return Tree[Tree[x].fa].ch[0] != x && Tree[Tree[x].fa].ch[1] != x; }
inline int judge (int x) { return Tree[Tree[x].fa].ch[1] == x; }
inline void connect (int x, int f, int dir) { Tree[x].fa = f, Tree[f].ch[dir] = x; }
inline void push_up (int x)
{
Tree[x].max = Tree[x].val;
if (Edge[Tree[ls].max].z > Edge[Tree[x].max].z) Tree[x].max = Tree[ls].max;
if (Edge[Tree[rs].max].z > Edge[Tree[x].max].z) Tree[x].max = Tree[rs].max;
}
inline void push_down (int x) { if (Tree[x].rev) swap(ls, rs), Tree[ls].rev ^= 1, Tree[rs].rev ^= 1, Tree[x].rev = 0; }
inline void rotate (int x)
{
int f = Tree[x].fa, anc = Tree[f].fa, dirx = judge(x), dirf = judge(f);
/**/ if (!is_root(f)) Tree[anc].ch[dirf] = x; Tree[x].fa = anc;
connect (Tree[x].ch[dirx ^ 1], f, dirx);
connect (f, x, dirx ^ 1);
/**/ push_up(f), push_up(x);
}
inline void splay (int x)
{
Stack[++top] = x; for (int y = x; !is_root(y); y = Tree[y].fa) Stack[++top] = Tree[y].fa;
/**/ while (top) push_down (Stack[top--]);
for (; !is_root(x); rotate (x)) if (!is_root(Tree[x].fa)) rotate (judge(x) == judge(Tree[x].fa) ? Tree[x].fa: x);
}

inline void access (int x) { for (int y = 0; x; y = x, x = Tree[x].fa) splay(x), rs = y, push_up(x); }
inline void make_root (int x) { access (x), splay (x), Tree[x].rev ^= 1; }
inline void split (int x, int y) { make_root(x), access(y), splay(y); }
inline void link (int x, int y) { make_root(x); Tree[x].fa = y; }
inline void cut (int x, int y) { split(x, y); Tree[x].fa = Tree[y].ch[0] = 0; push_up(y); }
/**/inline int query (int x, int y) { split(x, y); return Tree[y].max; }
inline void update (int x, int y)
{
int id = query(x, y), pos = S[mp(x, y)];
if (Edge[pos].z < Edge[id].z)
{
cut (Edge[id].x, id + N), cut (id + N, Edge[id].y);
link (Edge[pos].x, pos + N), link (pos + N, Edge[pos].y);
}
}
}

namespace DSU
{
int fa[Maxn];
inline void init (int maxn) { for (int i = 1; i <= maxn; ++i) fa[i] = i; }
inline int find (int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
inline void link (int x, int y) { fa[find(x)] = find(y); }
}

inline void Solve ()
{
DSU :: init (N);
for (int i = 1; i <= M; ++i)
if (!Edge[i].op)
{
if (DSU :: find(Edge[i].x) != DSU :: find(Edge[i].y))
{
LCT :: link (Edge[i].x, i + N), LCT :: link (i + N, Edge[i].y);
DSU :: link (Edge[i].x, Edge[i].y);
}
else LCT :: update (Edge[i].x, Edge[i].y);
}
for (int i = Q; i >= 1; --i)
{
if (Query[i].op == 1) Ans.pb(Edge[LCT :: query (Query[i].x, Query[i].y)].z);
else LCT :: update (Query[i].x, Query[i].y);
}
for (int i = Ans.size() - 1; i >= 0; --i) printf("%d\n", Ans[i]);
}

inline int cmp (node a, node b) { return a.z < b.z; }

inline void Input ()
{
N = read<int>(), M = read<int>(), Q = read<int>();

for (int i = 1; i <= M; ++i)
{
Edge[i].x = read<int>(), Edge[i].y = read<int>(), Edge[i].z = read<int>();
S[mp(Edge[i].x, Edge[i].y)] = S[mp(Edge[i].y, Edge[i].x)] = i;
Tree[N + i].val = Tree[N + i].max = i;
}

for (int i = 1; i <= Q; ++i)
{
Query[i].op = read<int>(), Query[i].x = read<int>(), Query[i].y = read<int>();
if (Query[i].op == 2) Edge[S[mp(Query[i].x, Query[i].y)]].op = 1;
}
}

int main()
{
#ifndef ONLINE_JUDGE
freopen("A.in", "r", stdin);
freopen("A.out", "w", stdout);
#endif
Input();
Solve();
return 0;
}

Debug

  • 67L:is_root(f)写成is_root(x)
  • 70L:忘记 push_up
  • 75L:写成push_down(top--)
  • 84L:返回值写错,返回的最大值而不是最大值的编号
感谢你的赞赏!