[树链剖分]hihocoder1883
描述
有一个无向图,有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相关推荐
- 【ZJOI2008】树的统计(树链剖分)
传送门 Solution: 就是树链剖分入门题啦~ // luogu-judger-enable-o2 #include<bits/stdc++.h> #define N 30005 #d ...
- 树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)
题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一 ...
- P1505 [国家集训队]旅游 树链剖分
题目链接 题意:树上更新某一点权值,更新两点简单路径权值,查询最大,最小,和 思路:思路应该比较简单,就是树链剖分后用线段树维护区间最大最小以及区间和. 但是本题比较特殊的是给的边权,转化为点权即可. ...
- 【模板】树链剖分 P3384
题目链接 //部分转自:https://www.luogu.org/problemnew/solution/P3384 初学树链剖分,感觉这个模板题还是容易理解的,但是实在是码量很大的. 知识点: 重 ...
- 树链剖分——线段树区间合并bzoj染色
线段树区间合并就挺麻烦了,再套个树链就更加鬼畜,不过除了代码量大就没什么其他的了.. 一些细节:线段树每个结点用结构体保存,pushup等合并函数改成返回一个结构体,这样好写一些 struct Seg ...
- bzoj1036: [ZJOI2008]树的统计Count 树链剖分
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从 ...
- SPOJ375(树链剖分)
题目:Query on a tree 题意:给定一棵树,告诉了每条边的权值,然后给出两种操作: (1)把第i条边的权值改为val (2)询问a,b路径上权值最大的边 分析:本题与HDU3966差不多, ...
- 洛谷3384:【模板】树链剖分——题解
https://www.luogu.org/problemnew/show/P3384 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 ...
- 树链剖分 or 根号分治 + dfs序 + 树状数组 ---- CF1254 D. Tree Queries
题目链接 题目大意: 问题转化: 很容易发现:假设修改的节点是vvv. 1.vvv的子树sonvson_vsonv直接加上(n−size[sonv])n×d\frac{(n-size[son_v]) ...
最新文章
- 用Python发一个高逼格的朋友圈
- STlink下载出现st-link usb communication error解决方法
- 在html中加入滚动条,html在div中显示滚动条
- Android常用的开源框架
- SpringBoot自动配置实现原理及源码解析(2.3.x)
- 保障健康睡眠的几种食疗法
- 微信端php 开发技术要求,PHP微信开发技术 - WebFalse文档托管平台
- java 字符串转成 json 数组并且遍历
- 在Linux中如何使用gdb调试C程序
- 雷军自述:我十年的程序员生涯
- TFC2017 腾讯Web前端大会参会小结
- python学习(八)----外星人入侵(项目篇)
- CentOS7安装无线网卡驱动和更新yum源
- python-合并两个txt文件
- 跨三服务器维护,DNF卢克跨区再度波动?策划:不是很想维护跨三服务器了
- HTML5网页设计基础——LOGO的制作
- android win7 共享网络打印机,win7设置局域网共享打印机
- JAVA:代码实现zip压缩
- Android CameraX 使用入门
- 龙之历程——学习易经系列(2)之初识乾卦
热门文章
- springboot集成Elasticsearch高亮显示(比较复杂)
- 为何 IntelliJ IDEA 比 Eclipse 更好
- 环境搭建 for 软件测试
- 利用openfire和smark的即时通信
- Java使用Function包策略模式,优化业务代码大量if...else语句
- 斯坦福大学卷积神经网络----Module 1 Lesson 2 线性分类
- 华为鸿蒙可以作为电脑系统吗,华为正式发布鸿蒙手机操作系统:让万物互联成为可能...
- DEseq2和edgeR的安装问题记录
- java 输出流转输入流
- android studio恢复代码