Luckyleaves's Blog

stay hungry,stay foolish greedy and lucky

CF687D Dividing Kingdom II

垃圾带权并查集。

说句闲话:初赛本校考还不给奖励名额是要干啥啊?!

Solution

首先考虑关押罪犯那道题,可以发现将所有的边从大到小排序,每次将边的两个点分到两边,第一个无法分的就是答案,我们考虑用并查集来维护这个过程,但是会出现一个问题,如果出现偶环,其实也是可以分的,此时只要交替放即可,所以我们带权并查集来维护,考虑到如果出现非法就不必再往下合并,所以我们用线段树来维护区间的可行边,每次查出来,然后合并,复杂度:$O(nq\log m+m\log m)$(由于很卡,并查集算成$O(1)$了)。

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
#include <bits/stdc++.h>
#define LL long long
#define PII pair<LL, LL>
using namespace std;
template <class T>
inline void read(T &res)
{
res = 0;
bool flag = 0;
char c = getchar();
while (c < '0' || '9' < c) { if (c == '-') flag = 1; c = getchar(); }
while ('0' <= c && c <= '9') res = (res << 3) + (res << 1) + (c ^ 48), c = getchar();
if (flag) res = -res;
}
template <class T, class... ARC>
inline void read(T &res, ARC &...com) { read(res), read(com...); }
template <class T>
void write(T res)
{
if (res < 0) putchar('-'), res = -res;
if (res > 9) write(res / 10);
putchar(res % 10 + '0');
}
template <>
inline void write(char c) { putchar(c); }
template <>
inline void write(char *s) { while (*s) putchar(*s++); }
template <class T, class... ARC>
inline void write(T res, ARC... com) { write(res), write(com...); }
const int N = 1005, M = 1e6 + 5;
int n, m, T;
struct Node{
int l, r;
vector<int> s;
}tr[M << 2];
struct Edge{
int o, u, val;
}e[M];
int fa[N], sz[N];
inline int find(int x)
{
if(fa[x] == x) return x;
int o = find(fa[x]);
sz[x] ^= sz[fa[x]];
return fa[x] = o;
}
inline bool cmp(int x, int y)
{
return e[x].val < e[y].val;
}
inline void merge(int u, int v)
{
if (find(u) == find(v)) return;
if (u > v) swap(u, v);
sz[fa[u]] ^= sz[u] ^ sz[v] ^ 1, fa[fa[u]] = fa[v];
}
inline void build(int x, int l, int r)
{
tr[x].l = l, tr[x].r = r;
vector<int> s;
for(int i = l;i <= r;i ++) s.emplace_back(i);
sort(s.begin(), s.end(), cmp);
for(int i = l;i <= r;i ++) fa[e[i].o] = e[i].o, fa[e[i].u] = e[i].u, sz[e[i].o] = 0, sz[e[i].u] = 0;
int flag = 0;
for(int i = s.size() - 1, o, u;i >= 0;i --)
{
o = e[s[i]].o, u = e[s[i]].u;
if(find(o) == find(u))
{
if(flag || (sz[o] + sz[u] + 1) % 2 == 0) continue;
tr[x].s.emplace_back(s[i]);
flag = 1;
break;
}
tr[x].s.emplace_back(s[i]);
merge(o, u);
}
if(l == r) return ;
int mid = l + r >> 1;
build(x << 1, l, mid);
build(x << 1 | 1, mid + 1, r);
}
inline vector<int> merge(vector<int> x, vector<int> y)
{
vector<int> s, res;
if(x.size() < y.size()) swap(x, y);
for(int i : y) x.emplace_back(i);
swap(s, x);
sort(s.begin(), s.end(), cmp);
for(int i : s) fa[e[i].o] = e[i].o, sz[e[i].o] = 0, fa[e[i].u] = e[i].u, sz[e[i].u] = 0;
for(int i = s.size() - 1, flag = 0, l, r;i >= 0;i --)
{
l = e[s[i]].o, r = e[s[i]].u;
if(find(l) == find(r))
{
if(flag || (sz[l] + sz[r] + 1) % 2 == 0) continue;
res.emplace_back(s[i]);
flag = 1;
break;
}
res.emplace_back(s[i]);
merge(l, r);
}
return res;
}
inline vector<int> query(int x, int l, int r)
{
if(l <= tr[x].l && tr[x].r <= r) return tr[x].s;
int mid = tr[x].l + tr[x].r >> 1;
vector<int> res;
if(l <= mid) res = merge(res, query(x << 1, l, r));
if(r > mid) res = merge(res, query(x << 1 | 1, l, r));
return res;
}
inline void work()
{
int l, r;
read(l, r);
vector<int> u = query(1, l, r);
for(int i = 1;i <= n;i ++) fa[i] = i, sz[i] = 0;
sort(u.begin(), u.end(), cmp);
for(int i = u.size() - 1, l, r;i >= 0;i --)
{
l = e[u[i]].o, r = e[u[i]].u;
if(find(l) == find(r) && (sz[l] + sz[r] + 1) % 2 != 0) return write(e[u[i]].val, '\n'), void();
merge(l, r);
}
puts("-1");
}
int main()
{
read(n, m, T);
for(int i = 1;i <= m;i ++) read(e[i].o, e[i].u, e[i].val);
build(1, 1, m);
while(T --) work();
return 0;
}