洛谷P4319 变化的道路
题意:给定图,每条边都有一段存在时间。求每段时间的最小生成树。
解:动态MST什么毒瘤...洛谷上还是蓝题...
线段树分治 + lct维护最小生成树。
对时间开线段树,每条边的存在时间在上面会对应到logn个区间。
我们先把这些边加到线段树对应节点上,但是不在lct上面加。最后扫一遍线段树。
扫到一个节点的时候把当前节点上的边加入lct,同时记录做了什么操作。回溯的时候还原操作。
最小生成树的权值不用lct维护子树和,直接用一个变量,加边删边的时候跟着修改即可。
这样复杂度就是nlog2n的...虽然常数上天了。
注意一下就是,回溯操作的时候顺序必须严格倒序。否则会出现一些情况导致re。
1 #include <cstdio> 2 #include <algorithm> 3 #include <vector> 4 5 typedef long long LL; 6 const int N = 500010, lm = 32766; 7 8 int fa[N], s[N][2], large[N], p[N], top; 9 bool rev[N]; 10 LL val[N]; 11 12 inline void pushup(int x) { 13 large[x] = x; 14 if(s[x][0] && val[large[x]] < val[large[s[x][0]]]) { 15 large[x] = large[s[x][0]]; 16 } 17 if(s[x][1] && val[large[x]] < val[large[s[x][1]]]) { 18 large[x] = large[s[x][1]]; 19 } 20 return; 21 } 22 23 inline void pushdown(int x) { 24 if(rev[x]) { 25 std::swap(s[x][0], s[x][1]); 26 if(s[x][0]) { 27 rev[s[x][0]] ^= 1; 28 } 29 if(s[x][1]) { 30 rev[s[x][1]] ^= 1; 31 } 32 rev[x] = 0; 33 } 34 return; 35 } 36 37 inline bool no_root(int x) { 38 return (s[fa[x]][0] == x) || (s[fa[x]][1] == x); 39 } 40 41 inline void rotate(int x) { 42 int y = fa[x]; 43 int z = fa[y]; 44 bool f = (s[y][1] == x); 45 46 fa[x] = z; 47 if(no_root(y)) { 48 s[z][s[z][1] == y] = x; 49 } 50 s[y][f] = s[x][!f]; 51 if(s[x][!f]) { 52 fa[s[x][!f]] = y; 53 } 54 s[x][!f] = y; 55 fa[y] = x; 56 57 pushup(y); 58 return; 59 } 60 61 inline void splay(int x) { 62 int y = x; 63 p[++top] = y; 64 while(no_root(y)) { 65 y = fa[y]; 66 p[++top] = y; 67 } 68 while(top) { 69 pushdown(p[top]); 70 top--; 71 } 72 73 y = fa[x]; 74 int z = fa[y]; 75 while(no_root(x)) { 76 if(no_root(y)) { 77 (s[z][1] == y) ^ (s[y][1] == x) ? 78 rotate(x) : rotate(y); 79 } 80 rotate(x); 81 y = fa[x]; 82 z = fa[y]; 83 } 84 pushup(x); 85 return; 86 } 87 88 inline void access(int x) { 89 int y = 0; 90 while(x) { 91 splay(x); 92 s[x][1] = y; 93 pushup(x); 94 y = x; 95 //printf("fa %d = %d \n", x, fa[x]); 96 x = fa[x]; 97 } 98 return; 99 } 100 101 inline void make_root(int x) { 102 access(x); 103 splay(x); 104 rev[x] = 1; 105 return; 106 } 107 108 inline int find_root(int x) { 109 access(x); 110 splay(x); 111 while(s[x][0]) { 112 x = s[x][0]; 113 pushdown(x); 114 } 115 return x; 116 } 117 118 inline void link(int x, int y) { 119 //printf("link %d %d \n", x, y); 120 make_root(x); 121 fa[x] = y; 122 return; 123 } 124 125 inline void cut(int x, int y) { 126 //printf("cut %d %d \n", x, y); 127 make_root(x); 128 access(y); 129 splay(y); 130 s[y][0] = fa[x] = 0; 131 pushup(y); 132 return; 133 } 134 135 inline int getMax(int x, int y) { 136 make_root(x); 137 access(y); 138 splay(y); 139 return large[y]; 140 } 141 // lct OVER 142 143 struct Edge { 144 int u, v; 145 LL val; 146 Edge(int x = 0, int y = 0, LL z = 0) { 147 u = x; 148 v = y; 149 val = z; 150 } 151 }edge[N]; 152 153 struct Node { 154 bool f; // 0 link 1 cut 155 int x; 156 Node(bool F = 0, int X = 0) { 157 f = F; 158 x = X; 159 } 160 }; 161 162 std::vector<int> id[N]; 163 std::vector<Node> v[N]; 164 int n; 165 LL Sum; 166 167 void add(int L, int R, int v, int l, int r, int o) { 168 if(L <= l && r <= R) { 169 id[o].push_back(v); 170 return; 171 } 172 int mid = (l + r) >> 1; 173 if(L <= mid) { 174 add(L, R, v, l, mid, o << 1); 175 } 176 if(mid < R) { 177 add(L, R, v, mid + 1, r, o << 1 | 1); 178 } 179 return; 180 } 181 182 void solve(int l, int r, int o) { 183 //printf("solve %d %d %d \n", l, r, o); 184 for(int i = 0; i < id[o].size(); i++) { 185 int t = id[o][i]; 186 int x = edge[t].u, y = edge[t].v; 187 int p = getMax(x, y); 188 if(val[p] < edge[t].val) { 189 continue; 190 } 191 cut(edge[p].u, p); 192 cut(edge[p].v, p); 193 link(x, t); 194 link(y, t); 195 v[o].push_back(Node(1, p)); 196 v[o].push_back(Node(0, t)); // pay attention! this must be behind 197 Sum -= val[p]; 198 Sum += val[t]; 199 //printf(" > push %d %d \n", t, p); 200 } 201 if(l == r) { 202 printf("%lld\n", Sum + 1); 203 } 204 else { 205 int mid = (l + r) >> 1; 206 solve(l, mid, o << 1); 207 solve(mid + 1, r, o << 1 | 1); 208 } 209 //printf(" -- solve %d %d %d \n", l, r, o); 210 for(int i = v[o].size() - 1; i >= 0; i--) { // this must be sleep 211 int t = v[o][i].x; 212 if(v[o][i].f) { 213 link(edge[t].u, t); 214 link(edge[t].v, t); 215 Sum += val[t]; 216 } 217 else { 218 cut(edge[t].u, t); 219 cut(edge[t].v, t); 220 Sum -= val[t]; 221 } 222 //printf(" -- > pop %d \n", t); 223 } 224 v[o].clear(); 225 return; 226 } 227 228 int main() { 229 230 scanf("%d", &n); 231 LL z; 232 for(int i = 1, x, y; i < n; i++) { 233 scanf("%d%d%lld", &x, &y, &z); 234 val[n + i] = z; 235 link(x, n + i); 236 link(n + i, y); 237 edge[n + i].u = x; 238 edge[n + i].v = y; 239 edge[n + i].val = z; 240 Sum += z; 241 } 242 int m; 243 scanf("%d", &m); 244 for(int i = 1, l, r; i <= m; i++) { 245 int t = 2 * n + i; 246 scanf("%d%d%lld%d%d", &edge[t].u, &edge[t].v, &edge[t].val, &l, &r); 247 val[t] = edge[t].val; 248 add(l, r, t, 1, lm, 1); 249 } 250 251 solve(1, lm, 1); 252 253 return 0; 254 }
AC代码
转载于:https://www.cnblogs.com/huyufeifei/p/10376484.html
洛谷P4319 变化的道路相关推荐
- 洛谷P1462 通往奥格瑞玛的道路 二分答案+最短路SPFA
洛谷P1462 通往奥格瑞玛的道路 二分答案+最短路SPFA 二分交费最多的一次的钱数 然后只将符合要求的边加入图中 如果到终点的最短路大于等于血量 或者直接起点不能到达终点 那么说明不符合要求 需要 ...
- 洛谷P1462 通往奥格瑞玛的道路 题解
洛谷P1462 通往奥格瑞玛的道路 题解 题目链接:P1462 通往奥格瑞玛的道路 题意:在艾泽拉斯,有 nnn 个城市.编号为 1,2,3,-,n1,2,3,\ldots,n1,2,3,-,n . ...
- 洛谷4438 [HNOI/AHOI2018]道路
标签:树形DP 题目 题目传送门 题目描述 W 国的交通呈一棵树的形状.W 国一共有n−1n - 1n−1个城市和nnn个乡村,其中城市从111到n−1n - 1n−1 编号,乡村从111到nnn编号 ...
- 洛谷-P1462-通往奥格瑞玛的道路
题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量. 有一天他醒来后发现自己居然到了联盟的主城暴风城. 在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛. 题目描述 在艾泽 ...
- 洛谷 P1462 通往奥格瑞玛的道路 Label: 最小化最大值 spfa (存多条边示例)
题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛 题目描述 在艾泽拉斯, ...
- NOIP2014洛谷P2296:寻找道路(bfs)
解析 杀鸡焉用AS47 做的巨差的一道题 WA3遍+写的巨麻烦+复杂度被吊打 qwq 说起来很玄学,但第一交之前就有一种强烈的预感觉得自己会WA 一开始像个傻子一样对有环图上记搜 WA了还不知道为啥- ...
- 洛谷P1462 通往奥格瑞玛的道路
题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量. 有一天他醒来后发现自己居然到了联盟的主城暴风城. 在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛. 题目描述 在艾泽 ...
- 洛谷 P1462 通往奥格瑞玛的道路
Description 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛 在艾泽拉 ...
- 洛谷 1462 通往奥格瑞玛的道路 题解
博客观赏效果更佳 题意简述 nnn个点mmm条边的无向图,点边均有权.给定bbb.请你找到一个从1到n的路使得边权和<=b且点权的最大值最小. 思路 二分+最短路.对于一个mid,把所有点权&l ...
最新文章
- Java:逐步读取/流式传输CSV文件
- php最新图片漏洞,2018最新PHP漏洞利用技巧
- 换掉 Postman + Swagger + JMeter,这 5 个 Java 项目绝了!
- mysql binlog查看工具_数据同步工具otter(一)谈谈binlog和canal
- std::auto_ptr简单使用
- 二种清空数据库的好方法
- java2048设计说明,Html5中的本地存储设计理念
- bash:pip:找不到命令
- java.util.stream.LongStream
- CSS border设置虚线可调节虚线间距
- 网站弹窗广告html,网站弹窗广告(彻底关闭浏览器的广告弹窗?)
- php64转码,Base64的编码转换方式
- 龙芯平台的播放器和浏览器硬解1080和4k视频
- 仿蓝色理想的“运行代码”功能
- CocosCreator之字体资源
- 深度学习双显卡配置_更新深度学习装备:双(1080Ti)显卡装机实录
- 教你玩转商业字体设计
- 谷歌57版本设置浏览器编码
- StringBuffer的理解
- Linux命令入门教程(三):文件基础篇