题目传送门

题意:定义$Tour \, Belt$为某张图上的一个满足以下条件的点集:①点集中至少有$2$个点②任意两点互相连通③图上两个端点都在这个点集中的边的权值的最小值严格大于图上只有一个端点在这个点集中的边的权值的最大值。现在给你一张$N$个点,$M$条边的图,请给出这张图上所有$Tour\,Belt$中包含的点数的和。$N \leq 5000 , M \leq \frac{N(N - 1)}{2}$


虽然这道题没有必要用$Kruskal$重构树来写,但是考%你赛的时候写$Kruskal$重构树的时候写挂了(LCA写错了),所以补上这个坑

因为我们需要某个连通块中所有边都大于其连向外面的边,所以考虑使用最大生成树的加边方式,每一次形成一个新的连通块的时候统计一次答案。可是我们不知道这个连通块中是否还有边没有被加进去,无法知道那些没有被加入的边是否会导致这个连通块的贡献变为$0$,所以实现有些麻烦(实际上根据这一点可以写出$O(N^2)$的并查集写法,然而咕咕咕咕咕)

我们自然地想到使用$Kruskal$重构树解决这个问题。在$Kruskal$重构树中,每个非叶子节点对应一个$Kruskal$过程中形成的连通块,而它的贡献就是这个子树中的叶子节点的个数。我们在非叶子节点中额外记录一个合并时的边权。在$Kruskal$重构树建好后,一遍$dfs$建好树上倍增,然后我们就可以考虑非树边对现有的连通块的影响了。

首先我们可以知道,在$Kruskal$重构树上,某条边的影响范围从两个端点的$LCA$开始,而它会使根到$LCA$路径上父亲对应边权大于等于当前边边权的点失去贡献,因为其父亲合并时的边权就是当前连通块中只连一个端点的边中最大的边权。可以知道这在$Kruskal$重构树上是一条链。我们就可以使用树上倍增找到满足这个条件的深度最低的点,通过树上差分对这一条链打上标记,最后遍历整棵树统计答案。

时间复杂度为$O(MlogN)$,理论上过不了实际上跑得飞快???

我的第一棵$Kruskal$重构树qaq

 #include<bits/stdc++.h>
 #define MAXM 1000010
 #define MAXN 5010
 using namespace std;

 inline int read() {
     ;
     ;
     char c = getchar();
     while(!isdigit(c)) {
         if(c == '-')
             f = ;
         c = getchar();
     }
     while(isdigit(c)) {
         a = (a << ) + (a << ) + (c ^ ');
         c = getchar();
     }
     return f ? -a : a;
 }

 struct Edge {
     int start , end , w;
 } Ed[MAXM];
 ][] , ch[MAXN << ][] , size[MAXN << ] , fa[MAXN << ] , dep[MAXN << ] , tag[MAXN << ] , now[MAXN << ];
 int N , M , cntNode , ans;
 bool vis[MAXM];

 bool cmp(Edge a , Edge b) {
     return a.w > b.w;
 }

 int find(int a) {
     return fa[a] == a ? a : (fa[a] = find(fa[a]));
 }

 void dfs(int now , int fa) {
     dep[now] = dep[fa] + ;
     to[now][] = fa;
      ; i <=  ; i++)
         to[now][i] = to[to[now][i - ]][i - ];
     ]) {
         dfs(ch[now][] , now);
         dfs(ch[now][] , now);
     }
 }

 inline int jumpToLCA(int p , int q) {
     if(dep[p] < dep[q])
         swap(p , q);
      ; i >=  ; i--)
          << i) >= dep[q])
             p = to[p][i];
     if(p == q)
         return p;
      ; i >=  ; i--)
         if(to[p][i] != to[q][i]) {
             p = to[p][i];
             q = to[q][i];
         }
     ];
 }

 int jump(int n , int w) {
      ; i >=  ; i--)
         if(now[to[n][i]] >= w)
             n = to[n][i];
     return n;
 }

 int Dfs(int now) {
     ]) {
         ]) + Dfs(ch[now][]);
         )
             ans += size[now];
         tag[now] = ;
         return t;
     }
     ;
 }

 int main() {
     for(int T = read() ; T ; T--) {
         dep[] = ans = ;
         memset(vis ,  , sizeof(vis));
         memset(ch ,  , sizeof(ch));
         memset(now ,  , sizeof(now));
         cntNode = N = read();
         M = read();
          ; i <= N ; i++) {
             fa[i] = i;
             size[i] = ;
         }
          ; i <= M ; i++) {
             Ed[i].start = read();
             Ed[i].end = read();
             Ed[i].w = read();
         }
         sort(Ed +  , Ed + M +  , cmp);
          ; i <= M ; i++) {
             int p = find(Ed[i].start) , q = find(Ed[i].end);
             if(p != q) {
                 fa[p] = fa[q] = fa[cntNode] = ++cntNode;
                 ch[cntNode][] = p;
                 ch[cntNode][] = q;
                 size[cntNode] = size[p] + size[q];
                 now[cntNode] = Ed[i].w;
                 if(now[p] == Ed[i].w){
                     tag[p]--;
                     tag[cntNode]++;
                 }
                 if(now[q] == Ed[i].w){
                     tag[q]--;
                     tag[cntNode]++;
                 }
                 vis[i] = ;
             }
         }
         dfs(cntNode , cntNode);
          ; i <= M ; i++)
             if(!vis[i]) {
                 int t = jumpToLCA(Ed[i].end , Ed[i].start);
                 int p = jump(t , Ed[i].w);
                 tag[t]--;
                 tag[p]++;
             }
         Dfs(cntNode);
         cout << ans << endl;
     }
     ;
 }

题外话:

论把

 inline int jumpToLCA(int p , int q) {
     if(dep[p] < dep[q])
         swap(p , q);
      ; i >=  ; i--)
          << i) >= dep[q])
             p = to[p][i];
     if(p == q)
         return p;
      ; i >=  ; i--)
         if(to[p][i] != to[q][i]) {
             p = to[p][i];
             q = to[q][i];
         }
     ];
 }

写成

 inline int jumpToLCA(int p , int q) {
     if(dep[p] < dep[q])
         swap(p , q);
      ; i >=  ; i--)
          << i) >= q)
             p = to[p][i];
     if(p == q)
         return p;
      ; i >=  ; i--)
         if(to[p][i] != to[q][i]) {
             p = to[p][i];
             q = to[q][i];
         }
     ];
 }

考%你赛还查不出来qwq

UVA1265 Tour Belt Kruskal重构树、倍增、树上差分的更多相关文章

  1. BZOJ5415[Noi2018]归程——kruskal重构树+倍增+堆优化dijkstra

    题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 n 个节点.m 条边的无向连通图(节点的编号从 1 至 n).我们依次用 l,a 描述一条边的长度.海 ...

  2. NOI2018Day1T1 归程 并查集 kruskal kruskal重构树 倍增表 Dijkstra

    原文链接https://www.cnblogs.com/zhouzhendong/p/NOI2018Day1T1.html 题目传送门 - 洛谷P4768 题意 给定一个无向连通图,有 $n$ 个点 ...

  3. BZOJ3732Network——kruskal重构树+倍增+LCA/最小生成树+倍增

    题目描述 给你N个点的无向图 (1 <= N <= 15,000),记为:1…N. 图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 & ...

  4. LOJ #2718. 「NOI2018」归程(Dijkstra + Kruskal重构树 + 倍增)

    题意 给你一个无向图,其中每条边有两个值 \(l, a\) 代表一条边的长度和海拔. 其中有 \(q\) 次询问(强制在线),每次询问给你两个参数 \(v, p\) ,表示在 \(v\) 出发,能开车 ...

  5. 【BZOJ 3732】 Network Kruskal重构树+倍增LCA

    Kruskal重构树裸题, Sunshine互测的A题就是Kruskal重构树,我通过互测了解到了这个神奇的东西... 理解起来应该没什么难度吧,但是我的Peaks连WA,,, 省选估计要滚粗了TwT ...

  6. LOJ.2718.[NOI2018]归程(Kruskal重构树 倍增)

    LOJ2718 BZOJ5415 洛谷P4768 Rank3+Rank1无压力 BZOJ最初还不是一道权限题... Update 2019.1.5 UOJ上被hack了....好像是纯一条链的数据过不 ...

  7. BZOJ 4242: 水壶(Kruskal重构树 + Bfs)

    题意 一块 \(h ∗ w\) 的区域,存在障碍.空地.\(n\) 个建筑,从一个建筑到另一个建筑的花费为:路径上最长的连续空地的长度. \(q\) 次询问:从建筑 \(s_i\) 到 \(t_i\) ...

  8. [luogu4768] [NOI2018] 归程 (Dijkstra+Kruskal重构树)

    [luogu4768] [NOI2018] 归程 (Dijkstra+Kruskal重构树) 题面 题面较长,这里就不贴了 分析 看到不能经过有积水的边,即不能经过边权小于一定值的边,我们想到了kru ...

  9. Luogu P4768 [NOI2018]归程(Dijkstra+Kruskal重构树)

    P4768 [NOI2018]归程 题面 题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 \(n\) 个节点. \(m\) 条边的无向连通图(节点的编 ...

随机推荐

  1. 《Inside C#》笔记(四) 类

    类是对数据结构和算法的封装. 一 类成员 类成员包括以下几类,作者在后面的章节会详细讲解. 字段(用来保存数据,可用static readonly const来修饰).方法(操作数据的代码).属性(用 ...

  2. LaTeX:图形的填充(生成阴影图形)

    将内网和外网看到的综合整理. 韦恩图Venn \documentclass{standalone} \usepackage{tikz} %导出为图片需要安装imagemagick %https://t ...

  3. JAVA学习笔记:注释、变量的声明和定义、

    本文内容: 注释 变量的声明和定义 成员变量和局部变量 首发时间:2018-03-16 15:59 注释: 单行注释:// 多行注释:/* - */ 变量: 变量是内存中的一个存储区域,变量的定义就是 ...

  4. 在ASP.NET Core 2.0 web项目中使用EntityFrameworkCore

    一.安装EFCode包 EFCore需要根据不同的数据库选择不同的数据库提供程序database provider,各数据库的包地址:https://docs.microsoft.com/zh-cn/ ...

  5. mysql 临时数据突然变大

    晚上收到紧报警,一台数据库服务器磁盘空间使用快速从50%使用率到80%.我们生产的数据库都磁盘是>2T 登录机器发现*.myd文件异常大 登入数据库查询进程 mysql>showproce ...

  6. 3.4Python数据处理篇之Numpy系列(四)---ndarray 数组的运算

    目录 目录 (一)数组与标量的运算 1.说明: 2.实例: (二)元素级的运算(一元函数) 1.说明: 2.实例: (三)数组级的运算(二元函数) 1.说明: 2.实例: 目录 1.数组与标量的运算 ...

  7. 解决Windows10或者其他版本Windows Update报错的问题

    最近更新系统,发现报错0x80248014,系统版本为redstone2(创意者更新). 总结发现,只要是windows各个版本自动更新报错的,如0x80开头的一系列错误,都可以通过如下步骤解决: 手 ...

  8. January 04th, 2018 Week 01st Thursday

    Just do what works for you, because there will always be someone who think differently. 就做你自己所能做的,因为 ...

  9. Properties集合_修改配置信息

    集合中的数据来自于一个文件  注意:必须要保证该文件中的数据是键值对.  需要使用到读取流 使用load()方法读取已有文件中的数据,存储到Properties集合中 public class Pro ...

  10. File类_常见的方法(获取系统根目录与指定目录的容量)

    获取系统根目录 import java.io.File; public class File_ListRoots { public static void main(String[] args) { ...