题目传送门

题意:定义$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. 安全测试 WEB安全测试手册

    WEB安全测试手册 By:授客 QQ:1033553122 欢迎加入软件性能测试交流QQ群:7156436 概述 Ø          目的 Ø          适用读者 Ø          适用 ...

  2. Expo大作战(三十九)--expo sdk api之 DocumentPicker,Contacts(获取手机联系人信息),Branch

    简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...

  3. JavaScript大杂烩15 - 使用JQuery(下)

    前面我们总结了使用各种selector拿到了jQuery对象了,下面就是对这个对象执行指定的行为了. 2. 操作对象 - 行为函数action 执行jQuery内置的行为函数的时候,JQuery自动遍 ...

  4. 使用Visual Studio Team Services进行压力和性能测试(二)——压力测试执行

    使用Visual Studio Team Services进行压力和性能测试(二)--压力测试执行 1.点击Run test将会该压力测试进行排队,我们将看到等待测试代理屏幕.Visual Studi ...

  5. [20180604]在内存修改数据(bbed).txt

    [20180604]在内存修改数据(bbed).txt --//以前曾经做过在内存修改数据,通过oradebug poke命令修改内存信息,相关链接:--//http://blog.itpub.net ...

  6. 03-13_WLST导航和定位MBean

    本文重点:WLST导航和定位MBean     MBean切换图 如上:红色的字体表示切换的命令.ls和cd是在当前树下切换,其他命令是在不同树之间切换. 其中: DomainMBeanServer有 ...

  7. python第三十六天-----类中的特殊成员方法

    __doc__ 查看尖的描述信息 __module__表示当前操作的对象所在的模块 __class__表示当前操作的对象所属的类 __init__构造方法 通过类创建对象自动执行 __del__析构方 ...

  8. python第六天 函数 python标准库实例大全

    今天学习第一模块的最后一课课程--函数: python的第一个函数: 1 def func1(): 2 print('第一个函数') 3 return 0 4 func1() 1 同时返回多种类型时, ...

  9. C# Aspose.Cells方式导入Excel文件

    读取Excel 类 我返回的是DataTable 类型 也可以返回DataSet类型 public class XlsFileHelper { public DataTable ImportExcel ...

  10. The Tomcat connector configured to listen on port 8080 failed to start. The port may already be in use or the connector may be misconfigured

    springboot 8080端口被占用报错:The Tomcat connector configured to listen on port 8080 failed to start. The p ...