Problem :
n個點m條邊有邊權的無向圖,有q個詢問,每次詢問權值在[L,R]內的邊組成的最小生成樹的權值和,強制在線。
n <= 1000, m <= 100000, q <= 100000
Solution :
參考了網上的一份題解
按照邊權從大到小加入邊,用LCT來維護最小生成樹。再用一棵權值主席樹,第i棵主席樹記錄表示權值大於等於 i 的邊所構成的最小生成樹邊權和。
對於每一個詢問[L, R]直接在第L棵主席樹的[L ,R]區間內統計答案。ios
對於每一個詢問[L, R],要將端點離散化成對應的邊權表示,要注意離散化後的區間應被原來的區間包含,而不是包含原來的區間。c++
#include <cstdio> #include <iostream> #include <algorithm> #include <cmath> #include <cstring> #include <string> #include <map> #include <vector> #include <queue> #include <cassert> using namespace std; #define f(i, x, y) for (int i = x; i <= y; ++i) #define fd(i, x, y) for (int i = x; i >= y; --i) #define rep(i, x, y) for (int i = x; i <= y; ++i) #define repd(i, x, y) for (int i = x; i >= y; --i) const int INF = 1e9 + 7; const int N = 300008; const int NN = N * 100; int n, m, q; void read(int &x) { char ch; for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar()); x = 0; for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0'; } struct edge { int u, v, w; bool operator < (const edge &b) const { return w > b.w; } }eg[N]; int fa[N], c[N][2], val[N], mx[N], rev[N], st[N]; int root[N], rtId[N], ls[NN], rs[NN]; long long tag[NN]; int num, total; int p[N]; int tot; bool isroot(int x) { return c[fa[x]][0] != x && c[fa[x]][1] != x; } void pushup(int x) { int l = c[x][0], r = c[x][1]; mx[x] = x; if (val[mx[l]] > val[mx[x]]) mx[x] = mx[l]; if (val[mx[r]] > val[mx[x]]) mx[x] = mx[r]; } void pushdown(int x) { int l = c[x][0], r = c[x][1]; if (rev[x]) { if (l) rev[l] ^= 1; if (r) rev[r] ^= 1; rev[x] ^= 1; swap(c[x][0], c[x][1]); } } void rotate(int x) { int y = fa[x], z = fa[y], l, r; if (c[y][0] == x) l = 0; else l = 1; r = l ^ 1; if (!isroot(y)) { if (c[z][0] == y) c[z][0] = x; else c[z][1] = x; } fa[x] = z; fa[y] = x; fa[c[x][r]] = y; c[y][l] = c[x][r]; c[x][r] = y; pushup(y); pushup(x); } void splay(int x) { int top = 0; st[++top] = x; for (int i = x; !isroot(i); i = fa[i]) st[++top] = fa[i]; while (top) pushdown(st[top--]); while (!isroot(x)) { int y = fa[x], z = fa[y]; if (!isroot(y)) { if (c[y][0] == x ^ c[z][0] == y) rotate(x); else rotate(y); } rotate(x); } } void access(int x) { for (int t = 0; x; t = x, x = fa[x]) { splay(x); c[x][1] = t; pushup(x); } } void rever(int x) { access(x); splay(x); rev[x] ^= 1; } void link(int u, int v) { rever(u); fa[u] = v; } void cut(int u, int v) { rever(u); access(v); splay(v); fa[c[v][0]] = 0; c[v][0] = 0; pushup(v); } int find(int u) { access(u); splay(u); while (c[u][0]) u = c[u][0]; return u; } int query(int u, int v) { rever(u); access(v); splay(v); return mx[v]; } void build(int &rt, int l, int r) { rt = ++total; ls[rt] = rs[rt] = tag[rt] = 0; if (l == r) return; int m = l + r >> 1; build(ls[rt], l, m); build(rs[rt], m + 1, r); } void insert(int &rt, int last, int pos, int val, int l, int r) { rt = ++total; ls[rt] = ls[last]; rs[rt] = rs[last]; tag[rt] = tag[last]; if (l == r) { tag[rt] += val; return; } int m = l + r >> 1; if (pos <= m) insert(ls[rt], ls[last], pos, val, l, m); if (m < pos) insert(rs[rt], rs[last], pos, val, m + 1, r); tag[rt] = tag[ls[rt]] + tag[rs[rt]]; } long long query(int rt, int L, int R, int l, int r) { if (L <= l && r <= R) { return tag[rt]; } long long res = 0; int m = l + r >> 1; if (L <= m) res += query(ls[rt], L, R, l, m); if (m < R) res += query(rs[rt], L, R, m + 1, r); return res; } void init() { read(n); read(m); for (int i = 1; i <= m; ++i) { read(eg[i].u); read(eg[i].v); read(eg[i].w); p[i] = eg[i].w; } sort(p + 1, p + m + 1); tot = unique(p + 1, p + m + 1) - p - 1; for (int i = 1; i <= m; ++i) eg[i].w = lower_bound(p + 1, p + tot + 1, eg[i].w) - p; } void clear() { for (int i = 1; i <= num; ++i) root[i] = 0; for (int i = 1; i <= tot + 5; ++i) rtId[i] = 0; for (int i = 1; i <= n + m; ++i) { fa[i] = c[i][0] = c[i][1] = val[i] = mx[i] = rev[i] = 0; } num = total = 0; } void work() { build(root[0], 1, tot); sort(eg + 1, eg + m + 1); for (int i = 1; i <= m; ++i) { int u = eg[i].u, v = eg[i].v, w = eg[i].w; if (find(u) == find(v)) { int t = query(u, v); cut(t, eg[t - n].u); cut(t, eg[t - n].v); rtId[w] = ++num; insert(root[num], root[num - 1], val[t], -p[val[t]], 1, tot); } val[i + n] = w; mx[i + n] = i + n; link(i + n, u); link(i + n, v); rtId[w] = ++num; insert(root[num], root[num - 1], w, p[w], 1, tot); } } void solve() { read(q); int ans = 0; for (int i = 1; i <= q; ++i) { int u, v; read(u); read(v); u -= ans; v -= ans; int l = lower_bound(p + 1, p + tot + 1, u) - p; int r = upper_bound(p + 1, p + tot + 1, v) - p - 1; if (r == tot + 1) r = tot; ans = query(root[rtId[l]], l, r, 1, tot); cout << ans << endl; } } int main() { int T; read(T); for (int cas = 1; cas <= T; ++cas) { init(); clear(); work(); solve(); } }