【LG3206】[HNOI2010]城市建设

题面

洛谷

题解

有一种又好想、码得又舒服的做法叫线段树分治+\(LCT\)

但是因为常数过大,无法跑过此题。

所以这里主要介绍另外一种玄学\(cdq\)分治

对时间进行分治

因为每次分治都必须要缩小数据规模

而我们这里貌似无法满足这个要求

引进了下面的玄学东西:

设当前边集的大小为\(n\),分治区间为\([l,r]\)

则对于分治区间内的边,我们有如下两种剪枝:

\((1)Contraction:\)

将现在所有分治区间内的边权设为\(-\infty\),做一遍最小生成树

那么我们在最小生成树里面的除开边权为\(-\infty\)的边都要选,称这些边为必选边

\((2)Reduction:\)

将现在所有分治区间内的边设为\(\infty\),做一遍最小生成树,

那么此时没有出现在最小生成树中间的边一定不会选到,称为无用边

那么我们每次的无用边、必选边就无需考虑了

我们再用\(cdq\)分治修改序列,就可以达到减小数据规模的目的啦

复杂度网上说是\(O(nlog^2)\),但是不会证啊。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
inline int gi() {
register int data = 0, w = 1;
register char ch = 0;
while (!isdigit(ch) && ch != '-') ch = getchar();
if (ch == '-') w = -1, ch = getchar();
while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
return w * data;
}
typedef long long ll;
const int INF = 1e9;
const int MAX_N = 5e4 + 5;
struct Mdy { int x, y; } p[MAX_N];
struct Edge { int u, v, w, id; } e[18][MAX_N], tmp[MAX_N], stk[MAX_N];
inline bool operator < (const Edge &l, const Edge &r) { return l.w < r.w; }
int N, M, Q, sum[18];
int a[MAX_N], c[MAX_N], fa[MAX_N], rnk[MAX_N];
ll ans[MAX_N];
int getf(int x) { return (x == fa[x]) ? x : fa[x] = getf(fa[x]); }
void unite(int x, int y) {
x = getf(x), y = getf(y);
if (x == y) return ;
if (rnk[x] != rnk[y]) (rnk[x] > rnk[y]) ? fa[y] = x : fa[x] = y;
else fa[x] = y, rnk[y]++;
}
void Set(int n, Edge *a) {
for (int i = 1; i <= n; i++) {
fa[a[i].u] = a[i].u;
fa[a[i].v] = a[i].v;
rnk[a[i].v] = rnk[a[i].u] = 1;
}
}
void Contraction(int &n, ll &val) {
int top = 0;
Set(n, tmp); sort(&tmp[1], &tmp[n + 1]);
for (int i = 1; i <= n; i++)
if (getf(tmp[i].u) ^ getf(tmp[i].v))
unite(tmp[i].u, tmp[i].v), stk[++top] = tmp[i];
Set(top, stk);
for (int i = 1; i <= top; i++)
if (stk[i].w != -INF && getf(stk[i].u) ^ getf(stk[i].v))
val += stk[i].w, unite(stk[i].u, stk[i].v);
top = 0;
for (int i = 1; i <= n; i++)
if (getf(tmp[i].u) ^ getf(tmp[i].v))
stk[++top] = (Edge){getf(tmp[i].u), getf(tmp[i].v), tmp[i].w, tmp[i].id};
for (int i = 1; i <= top; i++) c[tmp[i].id] = i, tmp[i] = stk[i];
n = top;
}
void Reduction(int &n) {
int top = 0;
Set(n, tmp); sort(&tmp[1], &tmp[n + 1]);
for (int i = 1; i <= n; i++)
if (getf(tmp[i].u) ^ getf(tmp[i].v))
unite(tmp[i].u, tmp[i].v), stk[++top] = tmp[i];
else if (tmp[i].w == INF) stk[++top] = tmp[i];
for (int i = 1; i <= top; i++) c[tmp[i].id] = i, tmp[i] = stk[i];
n = top;
}
void Div(int l, int r, int dep, ll val) {
int n = sum[dep];
if (l == r) a[p[l].x] = p[l].y;
for (int i = 1; i <= n; i++) {
e[dep][i].w = a[e[dep][i].id];
tmp[i] = e[dep][i], c[tmp[i].id] = i;
}
if (l == r) {
ans[l] = val, Set(n, tmp);
sort(&tmp[1], &tmp[n + 1]);
for (int i = 1; i <= n; i++)
if (getf(tmp[i].u) != getf(tmp[i].v))
unite(tmp[i].u, tmp[i].v), ans[l] += tmp[i].w;
return ;
}
for (int i = l; i <= r; i++) tmp[c[p[i].x]].w = -INF;
Contraction(n, val);
for (int i = l; i <= r; i++) tmp[c[p[i].x]].w = INF;
Reduction(n);
for (int i = 1; i <= n; i++) e[dep + 1][i] = tmp[i];
sum[dep + 1] = n;
int mid = (l + r) >> 1;
Div(l, mid, dep + 1, val);
Div(mid + 1, r, dep + 1, val);
}
int main () {
N = gi(), M = gi(), Q = gi();
for (int i = 1; i <= M; i++) e[0][i] = (Edge){gi(), gi(), a[i] = gi(), i};
for (int i = 1; i <= Q; i++) p[i] = (Mdy){gi(), gi()};
sum[0] = M; Div(1, Q, 0, 0);
for (int i = 1; i <= Q; i++) printf("%lld\n", ans[i]);
return 0;
}

【LG3206】[HNOI2010]城市建设的更多相关文章

  1. [HNOI2010]城市建设

    [HNOI2010]城市建设 玄学cdq O(nlog^2n)的动态最小生成树 其实就是按照时间cdq分治+剪枝(剪掉一定出现和不可能出现的边) 处理[l,r]之间的修改以及修改之后的询问,不能确定是 ...

  2. 【BZOJ2001】[HNOI2010]城市建设(CDQ分治,线段树分治)

    [BZOJ2001][HNOI2010]城市建设(CDQ分治,线段树分治) 题面 BZOJ 洛谷 题解 好神仙啊这题.原来想做一直不会做(然而YCB神仙早就切了),今天来怒写一发. 很明显这个玩意换种 ...

  3. BZOJ2001 HNOI2010 城市建设

    题目大意:动态最小生成树,可以离线,每次修改后回答,点数20000,边和修改都是50000. 顾昱洲是真的神:顾昱洲_浅谈一类分治算法 链接: https://pan.baidu.com/s/1c2l ...

  4. BZOJ2001 HNOI2010城市建设(线段树分治+LCT)

    一个很显然的思路是把边按时间段拆开线段树分治一下,用lct维护MST.理论上复杂度是O((M+Q)logNlogQ),实际常数爆炸T成狗.正解写不动了. #include<iostream> ...

  5. [HNOI2010] 城市建设_动态最小生成树(Dynamic_MST)

    这个题...暴力单次修改\(O(n)\),爆炸... $ $ 不过好在可以离线做 如果可以在 分治询问 的时候把图缩小的话就可以做了 硬着头皮把这个骚东西看完了 $ $ 动态最小生成树 然后,就把它当 ...

  6. 【CDQ分治】[HNOI2010]城市建设

    题目链接 线段树分治+LCT只有80 然后就有了CDQ分治的做法 把不可能在生成树里的扔到后面 把一定在生成树里的扔到并查集里存起来 分治到l=r,修改边权,跑个kruskal就行了 由于要支持撤销, ...

  7. Luogu 3206 [HNOI2010]城市建设

    BZOJ 2001 很神仙的cdq分治 先放论文的链接   顾昱洲_浅谈一类分治算法 我们考虑分治询问,用$solve(l, r)$表示询问编号在$[l, r]$时的情况,那么当$l == r$的时候 ...

  8. 洛谷P3206 [HNOI2010]城市建设

    神仙题 题目大意: 有一张\(n\)个点\(m\)条边的无向联通图,每次修改一条边的边权,问每次修改之后这张图的最小生成树权值和 话说是不是\(cdq\)题目都可以用什么数据结构莽过去啊-- 这道题目 ...

  9. P3206 [HNOI2010]城市建设 [线段树分治+LCT维护动态MST]

    Problem 这题呢 就边权会在某一时刻变掉-众所周知LCT不支持删边的qwq- 所以考虑线段树分治- 直接码一发 如果 R+1 这个时间修改 那就当做 [L,R] 插入了一条边- 然后删的边和加的 ...

随机推荐

  1. BeanDefinition的创建(BeanDefinitionHolder的创建)

    这个对另一篇章Bean Definition从加载.解析.处理.注册到BeanFactory的过程的扩展. Spring框架中BeanDefinition的继承结构. Spring框架中BeanDef ...

  2. 【[HAOI2011]向量】

    靠瞎猜的数学题 首先我们先对这些向量进行一顿组合,会发现\((a,b)(a,-b)\)可以组合成\((2a,0)\),\((b,-a)(b,a)\)可以组合成\((2b,0)\),同理\((0,2a) ...

  3. POJ2187 Beauty Contest(旋转卡壳)

    嘟嘟嘟 旋转卡壳模板题. 首先求出凸包. 然后\(O(n ^ 2)\)的算法很好想,但那就不叫旋转卡壳了. 考虑优化:直观的想是在枚举点的时候,对于第二层循环用二分或者三分优化,但实际上两点距离是不满 ...

  4. [19/04/27-星期六] GOF23_结构型模式(装饰模式、外观模式)

    一.装饰模式(decorator) 职责:动态的为一个对象增加新的功能. 是一种用于代替继承的技术,无须通过继承增加子类就能扩展对象的新功能.使用对象的关联关系代替继承关系,更加灵活,避免类体系的膨胀 ...

  5. linux使用秘钥登录(禁用root密码登录)

    目的:为了巩固线上外网服务器的安全,避免黑客攻击植入木马,初步决定禁用root密码登录(安全强度低),统一使用秘钥登录(4096位长度,安全性较高) 具体操作如下: 一.生成ssh秘钥: ssh-ke ...

  6. idea 注册码(2019)

    MTW881U3Z5-eyJsaWNlbnNlSWQiOiJNVFc4ODFVM1o1IiwibGljZW5zZWVOYW1lIjoiTnNzIEltIiwiYXNzaWduZWVOYW1lIjoiI ...

  7. 谷歌浏览器linux,windows下载

    https://www.chromedownloads.net/ 提取码自己行提取rpm安装包

  8. Linux下使用FIO测试磁盘的IOPS

    FIO是测试IOPS的非常好的工具,用来对硬件进行压力测试和验证,支持13种不同的I/O引擎,包括:sync,mmap, libaio, posixaio, SG v3, splice, null, ...

  9. 【hdu 3177 Crixalis's Equipment】 题解

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3177 \(describe\): 有一个山洞,山洞的容积最大为\(v\).现在你有\(n\)个物品,这 ...

  10. 【题解】洛谷P1273 有线电视网(树上分组背包)

    次元传送门:洛谷P1273 思路 一开始想的是普通树形DP 但是好像实现不大好 观摩了一下题解 是树上分组背包 设f[i][j]为以i为根的子树中取j个客户得到的总价值 我们可以以i为根有j组 在每一 ...