描述

有一个无向图,有n个点,m1条第一类边和m2条第二类边。第一类边有边权,第二类边无边权。请为第二类的每条边定义一个边权,使得第二类边可能全部出现在该无向图的最小生成树上,同时要求第二类边的边权总和尽可能大。
注:第二类边不会形成环

输入

第一行三个数n,m2,m1

接下来m2行,每行两个数,描述一条第二类边,分别表示两个端点接下来m1行,每行三个数,描述一条第一类边,分别表示两个端点和边权

对于30%的数据,n ≤ 5

对于60%的数据,n ≤ 1000

对于100%的数据,1 ≤ n ≤ 100000, m1 ≤ 2 × n, m2 < n

输出

输出一个数,表示第二类边的权值总和最大可能为多少。(若可能为无穷大则输出-1)

样例输入
5 2 3
1 2
4 5
2 3 100
3 4 100
1 5 1000
样例输出
2000

题解:

将所有第二类边权当作0处理,先构造出生成树。

之后对于不在生成树上的边e,我们尝试加入e,如果构成的环中有一条边大于e则将那条边用e代替更优。

所以我们构造出生成树后,令第二类边权值为x = inf,每次对于一条不在生成树中的边权值w,让环上的第二类边权值x = min(x, w),即树上的链赋值操作,树链剖分即可。

  1 #include <bits/stdc++.h>
  2
  3 #define ll long long
  4 #define ull unsigned long long
  5 #define st first
  6 #define nd second
  7 #define pii pair<int, int>
  8 #define pil pair<int, ll>
  9 #define pli pair<ll, int>
 10 #define pll pair<ll, ll>
 11 #define tiii tuple<int, int, int>
 12 #define pw(x) ((1LL)<<(x))
 13 #define lson l, m, rt<<1
 14 #define rson m+1, r, rt<<1|1
 15 #define sqr(x) ((x)*(x))
 16 #define SIZE(A) ((int)(A.size()))
 17 #define LENGTH(A) ((int)(A.length()))
 18 #define FIN freopen("A.in","r",stdin);
 19 #define FOUT freopen("A.out","w",stdout);
 20 using namespace std;
 21 /***********/
 22
 23 template<typename T>
 24 bool scan (T &ret) {
 25     char c;
 26     int sgn;
 27     if (c = getchar(), c == EOF) return 0; //EOF
 28     while (c != '-' && (c < '0' || c > '9') ) c = getchar();
 29     sgn = (c == '-') ? -1 : 1;
 30     ret = (c == '-') ? 0 : (c - '0');
 31     while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
 32     ret *= sgn;
 33     return 1;
 34 }
 35 template<typename N,typename PN>inline N flo(N a,PN b){return a>=0?a/b:-((-a-1)/b)-1;}
 36 template<typename N,typename PN>inline N cei(N a,PN b){return a>0?(a-1)/b+1:-(-a/b);}
 37 template<typename T>inline int sgn(T a) {return a>0?1:(a<0?-1:0);}
 38 template<class T> int countbit(const T &n) { return (n==0)?0:(1+countbit(n&(n-1))); }
 39 template <class T1, class T2>
 40 bool gmax(T1 &a, const T2 &b) { return a < b? a = b, 1:0;}
 41 template <class T1, class T2>
 42 bool gmin(T1 &a, const T2 &b) { return a > b? a = b, 1:0;}
 43 template <class T> inline T lowbit(T x) {return x&(-x);}
 44
 45 template<class T1, class T2>
 46 ostream& operator <<(ostream &out, pair<T1, T2> p) {
 47     return out << "(" << p.st << ", " << p.nd << ")";
 48 }
 49 template<class A, class B, class C>
 50 ostream& operator <<(ostream &out, tuple<A, B, C> t) {
 51     return out << "(" << get<0>(t) << ", " << get<1>(t) << ", " << get<2>(t) << ")";
 52 }
 53 template<class T>
 54 ostream& operator <<(ostream &out, vector<T> vec) {
 55     out << "("; for(auto &x: vec) out << x << ", "; return out << ")";
 56 }
 57 void testTle(int &a){
 58     while(1) a = a*(ll)a%1000000007;
 59 }
 60 const ll inf = 0x3f3f3f3f;
 61 const ll INF = 1e17;
 62 const int mod = 1e9+7;
 63 const double eps = 1e-5;
 64 const int N = 100000+10;
 65 const double pi = acos(-1.0);
 66
 67 /***********/
 68
 69
 70 struct Edge{
 71     int x, y, w;
 72 };
 73 Edge edge1[N+N], edge2[N];
 74 vector<pii> ve[N];
 75
 76 int n, m1, m2;
 77 int fa[N];
 78 int findf(int x) { return x == fa[x]? x: fa[x] = findf(fa[x]);}
 79
 80 int dfn, f[N], fdis[N], d[N], size[N], son[N], top[N], st[N], en[N];
 81 struct Node {
 82     int maxval;
 83     int tag;
 84 };
 85 Node T[N<<2];
 86 int a[N];
 87
 88 void pushup(int rt) {
 89     T[rt].maxval = max(T[rt<<1].maxval, T[rt<<1|1].maxval);
 90 }
 91 void pushdown(int rt) {//区间赋的值递增,之后赋的值必大于之前赋的值,故已有赋值则可跳过
 92     if(T[rt].tag) {
 93         if(!T[rt<<1].tag&&T[rt<<1].maxval > T[rt].tag)
 94             T[rt<<1].tag = T[rt].tag;
 95         if(!T[rt<<1|1].tag&&T[rt<<1|1].maxval > T[rt].tag)
 96             T[rt<<1|1].tag = T[rt].tag;
 97         T[rt].tag = 0;
 98     }
 99     if(T[rt].tag) {
100         if(!T[rt<<1].tag&&T[rt<<1].maxval > T[rt].tag)
101             T[rt<<1].tag = T[rt].tag;
102         if(!T[rt<<1|1].tag&&T[rt<<1|1].maxval > T[rt].tag)
103             T[rt<<1|1].tag = T[rt].tag;
104         T[rt].tag = 0;
105     }
106 }
107 void build(int l, int r, int rt) {
108     if(l == r) {
109         T[rt] = {a[l], 0};
110         return ;
111     }
112     int m = (l+r) >> 1;
113     build(lson);
114     build(rson);
115     pushup(rt);
116 }
117 void update(int L, int R, int val, int l, int r, int rt) {
118     if(L <= l&&r <= R) {
119         if(T[rt].tag == 0||T[rt].tag > val) T[rt].tag = val;
120         return ;
121     }
122     pushdown(rt);
123     int m = (l+r) >> 1;
124     if(L <= m) update(L, R, val, lson);
125     if(R > m) update(L, R, val, rson);
126 }
127
128 void dfs(int x){
129     size[x] = 1;
130     for(pii e: ve[x]) {
131         int y = e.st;
132         if(y != f[x]){
133             f[y] = x, d[y] = d[x]+1;
134             fdis[y] = e.nd;
135             dfs(y), size[x] += size[y];
136             if(size[y] > size[son[x]])
137                 son[x] = y;
138         }
139     }
140 }
141 void dfs2(int x, int y){
142     st[x] = ++dfn; top[x] = y;  a[dfn] = fdis[x];
143     if(son[x]) dfs2(son[x], y);
144     for(pii e: ve[x]) {
145         int y = e.st;
146         if(y != son[x]&&y != f[x])
147             dfs2(y, y);
148     }
149     en[x]=dfn;
150 }
151 //查询x,y两点的lca
152 int lca(int x,int y){
153     for(;top[x]!=top[y];x=f[top[x]])if(d[top[x]]<d[top[y]]) swap(x, y);
154     return d[x]<d[y]?x:y;
155 }
156 //x是y的祖先,查询x到y方向的第一个点
157 int lca2(int x, int y){
158     int t;
159     while(top[x]!=top[y])t=top[y],y=f[top[y]];
160     return x==y?t:son[x];
161 }
162 //对x到y路径上的点进行操作
163 void chain(int x, int y, int val){
164     for(;top[x]!=top[y];x=f[top[x]]){
165         if(d[top[x]]<d[top[y]]) swap(x, y);
166         //change(st[top[x]],st[x]);
167         update(st[top[x]], st[x], val, 1, n, 1);
168     }
169     if(d[x]<d[y]) swap(x, y);
170     //change(st[y],st[x]);
171     update(st[y], st[x], val, 1, n, 1);
172 }
173
174 long long ans;
175 bool solve(int l, int r, int rt) {
176     if(T[rt].maxval != inf) return true;
177     if(l == r) {
178         if(T[rt].tag == 0) return false;
179         ans += T[rt].tag;
180         return true;
181     }
182     pushdown(rt);
183     int m = (l+r) >> 1;
184     return solve(lson) && solve(rson);
185 }
186 int main() {
187     scanf("%d%d%d", &n, &m2, &m1);
188     for(int i = 0, x, y; i < m2; i++) {
189         scanf("%d%d", &x, &y);
190         edge2[i] = {x, y, 0};
191     }
192     for(int i = 0, x, y, w; i < m1; i++) {
193         scanf("%d%d%d", &x, &y, &w);
194         edge1[i] = {x, y, w};
195     }
196
197     sort(edge1, edge1+m1, [](Edge e1, Edge e2) {  return e1.w < e2.w; });
198     for(int i = 1; i <= n; i++) fa[i] = i;
199     for(int i = 0; i < m2; i++) {
200         Edge e = edge2[i];
201         int fx = findf(e.x), fy = findf(e.y);
202         if(fx != fy) {
203             fa[fx] = fy;
204             ve[e.x].push_back({e.y, inf});
205             ve[e.y].push_back({e.x, inf});
206         }
207     }
208     vector<Edge> tmp;
209     for(int i = 0; i < m1; i++) {
210         Edge e = edge1[i];
211         int fx = findf(e.x), fy = findf(e.y);
212         if(fx != fy) {
213             fa[fx] = fy;
214             ve[e.x].push_back({e.y, e.w});
215             ve[e.y].push_back({e.x, e.w});
216         }
217         else tmp.push_back(e);//将e.x -> e.y路径上的边w = min(w, e.w);
218     }
219
220     dfs(1);
221      dfs2(1, 1);
222     build(1, n, 1);
223     for(Edge e: tmp) {
224         int x = e.x, y = e.y, w = e.w;
225         int ancestor = lca(x, y);
226         if(ancestor != x) {
227             int xx = lca2(ancestor, x);
228             chain(xx, x, w);
229         }
230         if(ancestor != y) {
231             int yy = lca2(ancestor, y);
232             chain(yy, y, w);
233         }
234     }
235     printf("%lld\n", solve(1, n, 1)? ans: -1);
236     return 0;
237 }

View Code

转载于:https://www.cnblogs.com/dirge/p/10424347.html

[树链剖分]hihocoder1883相关推荐

  1. 【ZJOI2008】树的统计(树链剖分)

    传送门 Solution: 就是树链剖分入门题啦~ // luogu-judger-enable-o2 #include<bits/stdc++.h> #define N 30005 #d ...

  2. 树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)

    题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一 ...

  3. P1505 [国家集训队]旅游 树链剖分

    题目链接 题意:树上更新某一点权值,更新两点简单路径权值,查询最大,最小,和 思路:思路应该比较简单,就是树链剖分后用线段树维护区间最大最小以及区间和. 但是本题比较特殊的是给的边权,转化为点权即可. ...

  4. 【模板】树链剖分 P3384

    题目链接 //部分转自:https://www.luogu.org/problemnew/solution/P3384 初学树链剖分,感觉这个模板题还是容易理解的,但是实在是码量很大的. 知识点: 重 ...

  5. 树链剖分——线段树区间合并bzoj染色

    线段树区间合并就挺麻烦了,再套个树链就更加鬼畜,不过除了代码量大就没什么其他的了.. 一些细节:线段树每个结点用结构体保存,pushup等合并函数改成返回一个结构体,这样好写一些 struct Seg ...

  6. bzoj1036: [ZJOI2008]树的统计Count 树链剖分

    一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从 ...

  7. SPOJ375(树链剖分)

    题目:Query on a tree 题意:给定一棵树,告诉了每条边的权值,然后给出两种操作: (1)把第i条边的权值改为val (2)询问a,b路径上权值最大的边 分析:本题与HDU3966差不多, ...

  8. 洛谷3384:【模板】树链剖分——题解

    https://www.luogu.org/problemnew/show/P3384 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 ...

  9. 树链剖分 or 根号分治 + dfs序 + 树状数组 ---- CF1254 D. Tree Queries

    题目链接 题目大意: 问题转化: 很容易发现:假设修改的节点是vvv. 1.vvv的子树sonvson_vsonv​直接加上(n−size[sonv])n×d\frac{(n-size[son_v]) ...

最新文章

  1. 用Python发一个高逼格的朋友圈
  2. STlink下载出现st-link usb communication error解决方法
  3. 在html中加入滚动条,html在div中显示滚动条
  4. Android常用的开源框架
  5. SpringBoot自动配置实现原理及源码解析(2.3.x)
  6. 保障健康睡眠的几种食疗法
  7. 微信端php 开发技术要求,PHP微信开发技术 - WebFalse文档托管平台
  8. java 字符串转成 json 数组并且遍历
  9. 在Linux中如何使用gdb调试C程序
  10. 雷军自述:我十年的程序员生涯
  11. TFC2017 腾讯Web前端大会参会小结
  12. python学习(八)----外星人入侵(项目篇)
  13. CentOS7安装无线网卡驱动和更新yum源
  14. python-合并两个txt文件
  15. 跨三服务器维护,DNF卢克跨区再度波动?策划:不是很想维护跨三服务器了
  16. HTML5网页设计基础——LOGO的制作
  17. android win7 共享网络打印机,win7设置局域网共享打印机
  18. JAVA:代码实现zip压缩
  19. Android CameraX 使用入门
  20. 龙之历程——学习易经系列(2)之初识乾卦

热门文章

  1. springboot集成Elasticsearch高亮显示(比较复杂)
  2. 为何 IntelliJ IDEA 比 Eclipse 更好
  3. 环境搭建 for 软件测试
  4. 利用openfire和smark的即时通信
  5. Java使用Function包策略模式,优化业务代码大量if...else语句
  6. 斯坦福大学卷积神经网络----Module 1 Lesson 2 线性分类
  7. 华为鸿蒙可以作为电脑系统吗,华为正式发布鸿蒙手机操作系统:让万物互联成为可能...
  8. DEseq2和edgeR的安装问题记录
  9. java 输出流转输入流
  10. android studio恢复代码