题意
给定一张 n 个点 m 条边的无向连通图, 无重边, 无自环, 边有边权.
对于每条边, 我们求一个最大的 w : 尝试将它的权值改为 w , 而其他的边权保持不变时, 使得这条边一定在所有的最小生成树.
1 <= n, m <= 200000, 1 <= z <= 10 ^ 9 .
分析
这个问题与最小生成树有关, 我们首先考虑求出最小生成树, 然后与这个问题建立联系.
对于非树边 (u, v) , 如果它要变成所有最小生成树上的边, 那么它的最大值为 path(u, v) 上的最大边权 - 1 , 使用树上倍增.
对于树边 (u, v) , 如果它要变成所有最小生成树上的边, 那么它的最大值为连接这条边两端的联通块的非树边的最小边权 - 1 , 使用路径压缩.
实现
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #include <algorithm> 6 using namespace std; 7 #define F(i, a, b) for (register int i = (a); i <= (b); i++) 8 #define LL long long 9 #define db double 10 inline int rd(void) { 11 int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == ‘-‘) f = -1; 12 int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-‘0‘; return x*f; 13 } 14 15 const int N = 200005; 16 const int M = 400005; 17 const int S = 1050000; 18 const int W = 400000; 19 const int MOD = (int)1e9 + 7; 20 21 int n, tot, hd[N], nx[M], adj[M], key[M], Base[W + 5]; 22 LL S1; int S2, cnt[S], Max[S], Min[S]; 23 24 #define LC (x << 1) 25 #define RC (x << 1 | 1) 26 #define M ((L + R) >> 1) 27 inline void Up(int x) { 28 cnt[x] = cnt[LC] + cnt[RC]; 29 Max[x] = max(Max[LC], Max[RC]); 30 Min[x] = min(Min[LC], Min[RC]); 31 } 32 inline void Leaf(int x, int w) { 33 if (cnt[x] > 0) 34 Max[x] = Min[x] = w; 35 else Max[x] = 0, Min[x] = W+1; 36 } 37 void Build(int x, int L, int R) { 38 if (L == R) { 39 cnt[x] = Base[L]; 40 Leaf(x, L); 41 } 42 else { 43 Build(LC, L, M); 44 Build(RC, M+1, R); 45 Up(x); 46 } 47 } 48 inline void Modify(int x, int L, int R, int pos, int sign) { 49 if (L == R) { 50 cnt[x] += sign; 51 Leaf(x, L); 52 return; 53 } 54 pos <= M ? Modify(LC, L, M, pos, sign) : Modify(RC, M+1, R, pos, sign); 55 Up(x); 56 } 57 inline int Last(int x, int L, int R, db pos) { 58 if (pos < L) return W+1; 59 if (pos >= R) return Max[x]; 60 if (L == R) return W+1; 61 int tmp = Last(RC, M+1, R, pos); 62 return tmp == W+1 ? Last(LC, L, M, pos) : tmp; 63 } 64 inline int Next(int x, int L, int R, db pos) { 65 if (pos > R) return 0; 66 if (pos <= L) return Min[x]; 67 if (L == R) return 0; 68 int tmp = Next(LC, L, M, pos); 69 return !tmp ? Next(RC, M+1, R, pos) : tmp; 70 } 71 72 int main(void) { 73 #ifndef ONLINE_JUDGE 74 freopen("tree.in", "r", stdin); 75 #endif 76 77 n = rd(), tot = 1; 78 F(i, 1, n) { 79 int x = rd(), y = rd(), t = rd(); 80 nx[++tot] = hd[x], hd[x] = tot, adj[tot] = y, key[tot] = t; 81 nx[++tot] = hd[y], hd[y] = tot, adj[tot] = x, key[tot] = t; 82 Base[t]++; 83 S1 += t, S2 = (S2 + 1LL * t * t) % MOD; 84 } 85 Build(1, 1, W); 86 87 int m = rd(); 88 F(i, 1, m) { 89 int k = rd(); 90 if (k == 1) { 91 int x = rd(); 92 for (int k = hd[x]; k > 0; k = nx[k]) { 93 Modify(1, 1, W, key[k], -1), S1 -= key[k], S2 = (S2 - 1LL * key[k] * key[k]) % MOD; 94 key[k]++, key[k^1]++; 95 Modify(1, 1, W, key[k], +1), S1 += key[k], S2 = (S2 + 1LL * key[k] * key[k]) % MOD; 96 } 97 } 98 else { 99 db aver = 1.0 * S1 / n; 100 int x = Last(1, 1, W, aver); 101 int y = Next(1, 1, W, aver); 102 int z = (x == W+1 ? y : !y ? x : aver-x < y-aver ? x : y); 103 104 int tL = (S2 - 1LL * z * z) % MOD * (n - 1) % MOD; 105 int tR = (S1 % MOD - z) * (S1 % MOD - z) % MOD; 106 printf("%d\n", ((tL - tR) % MOD + MOD) % MOD); 107 } 108 } 109 110 return 0; 111 }
时间: 2024-10-04 11:03:28