Problem G. Pandaria
给定一个有 n n n条边的无向连通图,每条边有对应的边权,每个点有一个颜色,
问从一个点出发,经过不超过 w w w的边权,所能到达的点中,颜色出现次数做多且颜色编号最小的是什么颜色。
不超过某个权值所能到达的点,由此我们可以考虑建立升序 k r u s k a l kruskal kruskal重构树,然后从某个点倍增往上跳,直到不能跳为止,
这个时候我们所在的点的子树所包含的点就是我们能够到达的点了,
考虑用权值线段树来维护每一个点所代表的子树的信息,更新的时候我们只要往上进行线段树合并就行了。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, nn, m, Q, ff[N], value[N], color[N], fa[N][21], ans[N];
int root[N], ls[N << 5], rs[N << 5], maxn[N << 5], num;
vector<int> G[N];
struct Res {
int u, v, w;
void read() {
scanf("%d %d %d", &u, &v, &w);
}
bool operator < (const Res &t) const {
return w < t.w;
}
}edge[N];
void push_up(int rt) {
maxn[rt] = max(maxn[ls[rt]], maxn[rs[rt]]);
}
void update(int &rt, int l, int r, int x, int v) {
if (!rt) {
rt = ++num;
}
if (l == r) {
maxn[rt] += v;
return ;
}
int mid = l + r >> 1;
if (x <= mid) {
update(ls[rt], l, mid, x, v);
}
else {
update(rs[rt], mid + 1, r, x, v);
}
push_up(rt);
}
int merge(int x, int y, int l, int r) {
if (x == 0 || y == 0) {
return x | y;
}
if (l == r) {
maxn[x] += maxn[y];
return x;
}
int mid = l + r >> 1;
ls[x] = merge(ls[x], ls[y], l, mid);
rs[x] = merge(rs[x], rs[y], mid + 1, r);
push_up(x);
return x;
}
int query(int rt, int l, int r) {
if (l == r) {
return l;
}
int mid = l + r >> 1;
if (maxn[ls[rt]] == maxn[rt]) {
return query(ls[rt], l, mid);
}
else {
return query(rs[rt], mid + 1, r);
}
}
void dfs(int rt, int f) {
fa[rt][0] = f;
for (int i = 1; i <= 20; i++) {
fa[rt][i] = fa[fa[rt][i - 1]][i - 1];
}
if (rt <= n) {
update(root[rt], 1, n, color[rt], 1);
}
for (int to : G[rt]) {
if (to == f) {
continue;
}
dfs(to, rt);
root[rt] = merge(root[rt], root[to], 1, n);
}
ans[rt] = query(root[rt], 1, n);
}
int find(int rt) {
return ff[rt] == rt ? rt : ff[rt] = find(ff[rt]);
}
void kruskal() {
sort(edge + 1, edge + 1 + m);
for (int i = 1; i < 2 * n; i++) {
ff[i] = i;
}
for (int i = 1, cur = 1; i <= m && cur < n; i++) {
int u = find(edge[i].u), v = find(edge[i].v);
if (u ^ v) {
nn++, cur++;
ff[u] = ff[v] = nn;
G[nn].push_back(u), G[nn].push_back(v);
value[nn] = edge[i].w;
if (u <= n) {
value[u] = edge[i].w;
}
if (v <= n) {
value[v] = edge[i].v;
}
}
}
for (int i = 1; i <= num; i++) {
ls[i] = rs[i] = maxn[i] = 0;
}
for (int i = 1; i <= nn; i++) {
root[i] = 0;
}
num = 0;
dfs(nn, 0);
for (int i = 1; i <= nn; i++) {
G[i].clear();
}
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int T;
scanf("%d", &T);
for (int cas = 1; cas <= T; cas++) {
printf("Case #%d:\n", cas);
scanf("%d %d", &n, &m);
nn = n;
for (int i = 1; i <= n; i++) {
scanf("%d", &color[i]);
}
for (int i = 1; i <= m; i++) {
edge[i].read();
}
kruskal();
scanf("%d", &Q);
int res = 0;
while (Q--) {
int u, x;
scanf("%d %d", &u, &x);
u ^= res, x ^= res;
for (int i = 20; i >= 0; i--) {
if (fa[u][i] && value[fa[u][i]] <= x) {
u = fa[u][i];
}
}
res = ans[u];
printf("%d\n", res);
}
}
return 0;
}