[CF 827D] Best Edge Wight

题意

  给定一张 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

[CF 827D] Best Edge Wight的相关文章

Codeforces 827D Best Edge Weight 倍增 + 并查集 || 倍增 + 压倍增标记 (看题解)

Best Edge Weight 我们先找出一棵最小生成树, 对于非树边来说, 答案就是两点路径上的最大值 - 1, 这个直接倍增就能处理. 对于树边来说, 就是非树边的路径经过这条边的最小值 - 1, 这个可以用并查集压缩路径 或者 更压st表一样的方式更新. 感觉就是没想到先扣出来一个最小生成树, 而是往克鲁斯卡尔的过程中想了. #include<bits/stdc++.h> #define LL long long #define LD long double #define ull u

cf 609E.Minimum spanning tree for each edge

最小生成树,lca(树链剖分(太难搞,不会写)) 问存在这条边的最小生成树,2种情况.1.这条边在原始最小生成树上.2.加上这条半形成一个环(加上),那么就找原来这条边2端点间的最大边就好(减去).(sum+val-max) (代码冗长) 1 #include<bits/stdc++.h> 2 #define LL long long 3 #define N 100005 4 using namespace std; 5 inline int ra() 6 { 7 int x=0,f=1; c

(中等) CF 576D Flights for Regular Customers (#319 Div1 D题),矩阵快速幂。

In the country there are exactly n cities numbered with positive integers from 1 to n. In each city there is an airport is located. Also, there is the only one airline, which makes m flights. Unfortunately, to use them, you need to be a regular custo

CF 609E, 树链剖分

题目大意:给你一个联通无向图,问你包含某条边的最小生成树的大小是多少 解:做一个最小生成树,如果询问边在树上,则答案是最小生成树,否则则是这条边+树构成的环上去掉一条最大树边后得到的树.这里用树剖处理即可. 有个sb错误,因为问题是边权,而树剖的链一般是以点为单位,如果采用边权下放到点的技巧的话,注意lca的点权不要计算进来. 1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #incl

cf 434d Nanami&#39;s Power Plant 网络流

题目大意就是有n个发电机,每个发电机有l到r个档位可供选择,每个档位的输出功率是已知的,另外还有一些限制条件,形式为xu ≤ xv + d,表示发电机u的档位要小于v的档位加d,d是一个已知的整数.求n个发电机的最大功率. 假设没有最后那个限制条件,那么对于每个发电机i拆点成l-1,l...到r相邻两档位连边为max-f(i),f(i)是档位i的输出功率,max是一个大数,大于等于所有档位的输出功率.l-1与源点连inf的边,r与汇点连inf的边.假设最大流为flow,那么max*n-flow就

cf Round 613

A.Peter and Snow Blower(计算几何) 给定一个点和一个多边形,求出这个多边形绕这个点旋转一圈后形成的面积.保证这个点不在多边形内. 画个图能明白 这个图形是一个圆环,那么就是这个点距离多边形边缘最远的距离形成的圆面积减去这个点距离多边形边缘最近的距离形成的圆面积.我们可以得出距离最远的点一定是多边形的顶点.而距离最近的点不一定是多边形的顶点,但是在多边形的边上.我们用勾股定理判断点与每条边形成的三角形的两边角.如果有一个边角是钝角,则表示距离最近的点是顶点.如果都是锐角,则

B. Mr. Kitayuta&#39;s Colorful Graph (CF #286 (Div. 2) 并查集)

B. Mr. Kitayuta's Colorful Graph time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Mr. Kitayuta has just bought an undirected graph consisting of n vertices and m edges. The vertices of the g

CF 505B Mr. Kitayuta&#39;s Colorful Graph(最短路)

题意  求两点之间有多少不同颜色的路径 范围比较小  可以直接floyd #include<cstdio> #include<cstring> using namespace std; const int N = 105; int d[N][N][N], ans; int main() { int a, b, c, n, m, q; while(~scanf("%d%d", &n, &m)) { memset(d, 0, sizeof(d));

【CF刷题】14-05-12

Round 236 div.1 A:只需要每个点连接所有比他大的点,知道边用完为止. //By BLADEVIL #include <cmath> #include <cstdio> #define maxn 25; using namespace std; int main() { int task; scanf("%d",&task); while (task--) { int n,p; scanf("%d%d",&n,&