2015蓝桥杯C++A组——灾后重建

2015 年 蓝桥杯 A 组 C/C++ 第十题 灾后重建 【最小生成树 + LCA倍增 + 线段树维护区间max】 交题地址 详细复杂度做法解释 这是hard版本的. AC Codeconst int maxn = 5e4+5; const int maxm = 2e5 + 5; int up[maxn][23], maxx[maxn][23]; int deep[maxn], dis[maxn]; int cnt, head[maxn]; int n, m, q; struct node { in 阅读详情

灾后重建题目链接

问题描述

【题目描述】
在这里插入图片描述
【输入】
在这里插入图片描述
【输出】
在这里插入图片描述
【样例输入】

7 10 4
1 3 10
2 6 9
4 1 5
3 7 4
3 6 9
1 5 8
2 7 4
3 2 10
1 7 6
7 6 9
1 7 1 0
1 7 3 1
2 5 1 0
3 7 2 1

【样例输出】

9
6
8
8

题目解析

最小生成树简单算法

对于每一次问询,关注若干点后,我们需要按照最小生成树的方法生成n-1条边,此时关注点全部连通,然后求出其中的最大边就是答案。

倍增法优化最小生成树

新思路

  1. 首先生成最小生成树 M S T MST MST;
  2. 对每一次问询都要将关注点放入 M S T MST MST;
  3. 维护 m a x c o s t max{cost} maxcost;
    在维护 m a x c o s t max{cost} maxcost用到倍增法求最近公共祖先lca,倍增法就是要用额外的数据来存放每一个点。 f f [ i ] [ j ] ff[i][j] ff[i][j]表示点i向上移动 2 i 2^i 2i次到达节点的标号。

倍增法LCA

  1. 对 f f [ ] [ ] ff[][] ff[][]数组进行预处理,用到了 d f s dfs dfs算法;
  2. 求 l c a lca lca,将 a a a和 b b b调到同一个高度;
  3. 在2的过程中维护 m a x max max、 s u m sum sum、 a v g avg avg、 m i n min min。

C++代码

最小生成树简单算法

#include<bits/stdc++.h>
using namespace std;
int N,M,Q;
const int MaxM = 2*10^5;
const int MaxN = 50001;
struct Edge //边的抽象
{
    int from,to,cost; //起点终点代价
    Edge(int from,int to,int cost)
    {
        this->from = from;
        this->to = to;
        this->cost = cost;
    }
};
bool cmp(Edge *e1,Edge *e2)
{
    return e1->cost<e2->cost;
}
Edge *edges[MaxM];
//并查集
struct UFNode
{
    UFNode *parent;
    UFNode():parent(NULL){}
};
UFNode *find(UFNode *p)
{
    if(p->parent==NULL) return p;
    set<UFNode*> path;
    while(p->parent!=NULL)
    {
        path.insert(p);
        p = p->parent;
    }
    set<UFNode *>::iterator iter = path.begin();
    while(iter!=path.end())
    {
        (*iter)->parent=p;
        iter++; //指针后移
    }
    return p;
}
void merge(UFNode *p1,UFNode *p2) //并查集合并
{
    find(p2)->parent = find(p1);
}
UFNode ufnodes[MaxN]; //并查集的节点,一开始各自独立
void easy(int l,int r,int mod,int c)
{
    for(int j=0;j<=N;j++) ufnodes[j].parent = NULL; //重新初始化NULL
    //逐步加入边到最小生成树中
    for(int i=0;i<M;i++)
    {
        Edge *pEdge = edges[i];
        int from = pEdge->from;
        int to = pEdge->to;
        int cost = pEdge->cost;
        if(find(&ufnodes[from])==find(&ufnodes[to])) continue; //如果这两个点已经在一棵树上就不采纳
        else merge(&ufnodes[from],&ufnodes[to]); //并查集合并
        UFNode * parent = NULL;
        bool isOk = true;
        for(int i=l;i<=r;i++)
        {
            if(i%mod==c) //i值关注点的编号
            {
                if(parent==NULL) parent = find(&ufnodes[i]); //第一个关注点的老大
                else if(parent!=find(&ufnodes[i])) //没有联通
                {
                    isOk = false;
                    break;
                }
            }
        }
        if(isOk) //关注点都联通了
        {
            printf("%d\n",cost);
            break;
        }
    }
}
int main()
{
    scanf("%d %d %d",&N,&M,&Q);
    for(int i=0;i<M;i++)
    {
        int a,b,c;
        scanf("%d %d %d",&a,&b,&c);
        Edge *e = new Edge(a,b,c);
        edges[i] = e;
    }
    sort(edges,edges+M,cmp); //排序
    for(int i=0;i<Q;i++)
    {
        int l,r,mod,c;
        scanf("%d %d %d %d",&l,&r,&mod,&c);
        easy(l,r,mod,c);
    }
    return 0;
}

倍增法优化最小生成树代码

#include<bits/stdc++.h>
using namespace std;
int N,M,Q;
const int MaxM = 2*10^5;
const int MaxN = 50001;
int ff[MaxN][17]; //ff[i][j]表示标号为i的节点往根节点的方向移动2^i次达到的节点编号
int mm[MaxN][17]; //mm[i][j]指的是标号为i的节点往根节点的方向移动2^i次过程中的最大权
int depth[MaxN]; //记录每个点在mst中的深度
int vis[MaxN]; //记录耨个是否被访问过
struct Edge //边的抽象
{
    int from,to,cost; //起点终点代价
    Edge(int from,int to,int cost)
    {
        this->from = from;
        this->to = to;
        this->cost = cost;
    }
};
bool cmp(Edge *e1,Edge *e2)
{
    return e1->cost<e2->cost;
}
Edge *edges[MaxM];
//并查集
struct UFNode
{
    UFNode *parent;
    UFNode():parent(NULL){}
};
UFNode *find(UFNode *p)
{
    if(p->parent==NULL) return p;
    set<UFNode*> path;
    while(p->parent!=NULL)
    {
        path.insert(p);
        p = p->parent;
    }
    set<UFNode *>::iterator iter = path.begin();
    while(iter!=path.end())
    {
        (*iter)->parent=p;
        iter++; //指针后移
    }
    return p;
}
void merge(UFNode *p1,UFNode *p2) //并查集合并
{
    find(p2)->parent = find(p1);
}
UFNode ufnodes[MaxN]; //并查集的节点,一开始各自独立
int maxUsingLca(int a,int b) //倍增法求lca顺便求max权重
{
    int ans = -1;
    if(depth[a]<depth[b]) //将a的深度调到更深
    {
        int t=a;
        a=b;
        b=t;
    }
    int k=depth[a]-depth[b]; //将a调到和b同一高度
    for(int i=0;(1<<i)<=k;i++)
    {
        if((1<<i)&k)
        {
            ans = max(ans,mm[a][i]);
            a = ff[a][i];
        }
    }
    //至此a和b已经在同一层上
    for(int j=16;j>=0;j--)
    {
        if(ff[a][j]==ff[b][j]) continue;
        else
        {
            ans = max(ans,mm[a][j]);
            ans = max(ans,mm[b][j]);
            a = ff[a][j];
            b = ff[b][j];
            break;
        }
    }
    ans = max(ans,mm[a][0]);
    ans = max(ans,mm[b][0]); //再往上走一步就得到了lca
    return ans;
}
void mid(int l,int r,int mod,int c)
{
    int ans = -1;
    int left = l-l%mod+c;
    if(left<l) left += mod;
    for(;left+mod<=r;left+=mod)
    {
        ans = max(ans,maxUsingLca(left,left+mod));
    }
    printf("%d\n",ans);
}
//最小树的生成及表示
vector<Edge *> mst[MaxN];
void buildMST()
{
    int cnt = 0; //已加入边的数量
    //逐步加入边到最小生成树中
    for(int i=0;i<M;i++)
    {
        Edge *pEdge = edges[i];
        int from = pEdge->from;
        int to = pEdge->to;
        int cost = pEdge->cost;
        if(find(&ufnodes[from])==find(&ufnodes[to])) continue; //如果这两个点已经在一棵树上就不采纳
        else
        {
            merge(&ufnodes[from],&ufnodes[to]); //并查集合并
            cnt++;
            mst[from].push_back(pEdge);
            Edge *other = new Edge(to,from,cost);
            mst[to].push_back(other);
            if(cnt==N-1) //构建完成
            {
                break;
            }
        }
    }
}
void dfs(int start,int parent,int d) //start表示开始点编号,parent表示父结点编号,d表示这个点的深度
{
    depth[start] = d+1;
    vis[start] = 1;
    //向上走
    for(int i=1;i<17;i++)
    {
        ff[start][i] = ff[ff[start][i-1]][i-1];
        mm[start][i] = max(mm[start][i-1],mm[ff[start][i-1]][i-1]);
    }
    //向下递归找到所有儿子
    for(int i=0;i<mst[start].size();i++)
    {
        Edge *child = mst[start][i]; //儿子
        if(vis[child->to]) continue;
        ff[child->to][0] = start;
        mm[child->to][0] = child->cost;
        dfs(child->to,start,d+1);
    }
}
void preLca()
{
    ff[1][0] = 1; //定义1号节点为树的根节点
    mm[1][0] = 0; //定义1号节点为根节点
    dfs(1,1,0);
}
int main()
{
    scanf("%d %d %d",&N,&M,&Q);
    for(int i=0;i<M;i++)
    {
        int a,b,c;
        scanf("%d %d %d",&a,&b,&c);
        Edge *e = new Edge(a,b,c);
        edges[i] = e;
    }
    sort(edges,edges+M,cmp); //排序
    buildMST(); //生成最小树
    preLca(); //为倍增法做预处理
    for(int i=0;i<Q;i++)
    {
        int l,r,mod,c;
        scanf("%d %d %d %d",&l,&r,&mod,&c);
        mid(l,r,mod,c);
    }
    return 0;
}
2015年蓝桥杯C/C++省赛大学A组 灾后重建 (树上倍增最值+线段树) 题目链接 100分的做法: 当p>sqrt(n)时, 这时候%p=c的点不超过k个, 直接倍增求路径最值就好了 当p<=sqrt(n)时,将询问离线, 按照p和c从小到大排序,同时处理出所有p相同且c相同的区间询问 对于同一个p[i]和c[i],将所有%p[i]=c[i]的点, 两两(c[j]和c[j]+p)求路径最大值, 并将这个相邻最大值更新到线段树上, 对于一个区间的询问,... 阅读详情

相关推荐

[蓝桥杯解题报告]第六届蓝桥杯大赛省赛2015(软件类)真题C++A组 Apare_xzc

蓝桥杯第六届(2015年)省赛软件类C++A组解题报告 Apare_xzc 2020/3/12 1. 方程整数解 分析:         dfs即可。0^2 + 10^2 +30^2 = 1000 代码: #include <bits/stdc++.h> using namespace st...

Apare_xzc的博客 675

【灾后重建】蓝桥杯第六届省赛C/C++大学A组(并查集+Kruskal算法)

Pear市一共有N个居民点,居民点之间有M条双向道路相连。这些居民点两两之间都可以通过双向道路到达。这种情况一直持续到最近,一次严重的地震毁坏了全部M条道路。

KI的博客 8万+

记录一下本地部署Dify的坑

1. 截止2025-3-4为止,请注意,不要直接拉Dify的1.0.0版本。请先试用0.15.3版本。1.0.0有一个bug需要解决。3. 请使用docker-ce 新版本,docker-engine等老版本可能会有部分容器启动脚本执行莫名报错。2. 注意,请使用docker-compose V2版本,或者V1较高版本,否则会导致解析官方yml模板错误。

哈利路亚的收藏夹 5346

蓝桥杯试题——灾后重建

蓝桥杯试题——灾后重建 #include<iostream> #include<cstring> int N, M, Q; int x; int C; int visited[5002]; int p[5002]; using namespace std; struct Map { int arc[5002][5002]; int vexnum; int arcnum; }; Map map; void Init() { for (int i = 0; i <

qq_46586095的博客 584

Window系统下搭建GIT本地服务器

这是一篇在window下搭建git本地服务器的教程,带你一步步搭建出本地的git服务器。

qwer971211的博客 2万+

GitLab教程(四):分支(branch)和合并(merge)

命令进行合并时,Git具备一定的智能自动化处理能力:如果一个分支仅修改了文件A,而另一个分支独立地修改了文件B,Git能够无缝整合这些更改,自动完成合并过程——即最终的代码既包含了对A文件的修改也包含了对B文件的修改。同样地,若两个分支虽然都修改了同一个文件,但涉及的是文件中互不重叠的部分,比如一个改动发生在第一行,另一个则在第二行,Git同样能巧妙地自动合并这些非冲突性修改。获取了远程分支的最新变化,或者当你想要合并本地的一个分支到当前分支时,就会用到这个命令。,默认会尝试合并远程分支到当前分支。

TracyCoder的博客 7886

灾后重建(C++,Floyd)

floyd算法的变形应用

m0_74036684的博客 571

使用基于python的neurora进行表征相似性分析(RSA)

发现了一款用于表征分析的Python API,还是挺方便的,这里简单介绍一下进行表征相似性分析的使用方法。

zjh12312311的博客 2766

2015年第六届蓝桥杯省赛C/C++ A组 灾后重建题解(100分)

本题从 Big Small 分界出发,到最后发现其实并不需要 Big Small 分界,直接建简化线段树的复杂度也是没有问题的,真是挺有趣的。

——Light! 1728

Ubuntu 24.04.3 LTS 安装 OpenClaw 图文版

OpenClow安装指南

qq_17204557的博客 2551

MMCV安装后报错‘from mmcv import Config’?别慌,这是MMCV 2.0的锅!快速降级回退MMCV 1.x全指南

本文详细解析了MMCV 2.0版本升级导致的‘from mmcv import Config’报错问题,提供了从诊断到降级回退MMCV 1.x的完整解决方案。通过pip和OpenMIM工具链的实操指南,帮助开发者快速解决版本冲突,确保项目稳定运行。

weixin_29102619的博客 263

蓝桥杯——灾后重建

灾后重建Pear市一共有N(&lt;=50000)个居民点,居民点之间有M(&lt;=200000)条双向道路相连。这些居民点两两之间都可以通过双向道路到达。这种情况一直持续到最近,一次严重的地震毁坏了全部M条道路。震后,Pear打算修复其中一些道路,修理第i条道路需要Pi的时间。不过,Pear并不打算让全部的点连通,而是选择一些标号特殊的点让他们连通。Pear有Q(&lt;=50000)次询问,...

志远的博客 2251

【2022】人工智能☆✨

1. 朴素⻉叶斯⽅法是⼀种 ( ) ⽅法。A.机器学习的分类B.不确定性推理C.知识表示答案:A解析:朴素贝叶斯分类器是基于贝叶斯定理与特征条件独立假设的分类方法。它通过学习训练数据集来预测未知数据的类别标签,因此属于机器学习中的监督学习分类方法。选项B不确定性推理和选项C知识表示虽然与朴素贝叶斯方法有一定的关联,但它们并不是朴素贝叶斯方法的主要应用领域或定义特性。2. 关于启发式搜索描述正确的是 ( )。

super_mochi1 400

蓝桥杯2015c++A组真题&代码第十题灾后重建

蓝桥杯2015c++A组真题&amp;代码第十题灾后重建 下面结合 kruskal 最小生成树算法 + 倍增法求解 关于倍增法可以参考: https://blog.youkuaiyun.com/lw277232240/article/details/72870644 /* 灾后重建 Pear市一共有N(&lt;=50000)个居民点,居民点之间有M(&lt;=200000)条双向道路相连。这些...

Willen_的博客 1348

Google Earth Engine(GEE)——MOD09A1/MOD11A2/MOD13A1不同的QA波段去云进行分析

​​​​​​​大多数光学卫星图像产品都带有一个或多个 QA 波段,允许用户评估每个像素的质量并提取满足其要求的像素。QA 波段最常见的应用是提取有关多云像素的信息并对其进行屏蔽。但是 QA 波段包含大量其他信息,可以帮助您从分析中删除低质量数据。通常,QA 频带中包含的信息存储为按位标志。在这篇文章中,我将介绍与位运算相关的基本概念,以及如何使用位掩码提取和屏蔽特定的质量指标。

此星光明博客 4576

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

2015年第六届蓝桥杯【省赛C/C++ A组】刷题报告(C++描述)

2015年第六届蓝桥杯【省赛C/C++ A组】做题记录,保持手感,专注备赛。

KI的博客 8万+

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

2015年第四届C/C++ A组蓝桥杯省赛真题

这里是蓝桥杯历年的题目专栏,将会陆续更新将往年真题以及解答发布出来,欢迎各位小伙伴关注我吖,你们的点赞关注就是给我最好的动力!!! 每天更新一届真题,敬请期待 蓝桥杯历年真题及详细解答 目录第一题:方程整数解第二题:星系炸弹第三题:奇妙的数字第四题:格子中输出第五题:九数组分数第六题:牌型种数第七题:手链样式第八题:饮料换购第九题:垒骰子第十题:灾后重建 第一题:方程整数解 题目描述 方程: a^2 + b^2 + c^2 = 1000 (或参见【图1.jpg】) 这个方程有整数解吗?有:a,b,c=.

戎码一生的博客 6273

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

2015 【第六届蓝桥杯 省赛】C/C++ A组

目录 第一题:方程整数解 第二题:星系炸弹 第三题:奇妙的数字 第四题:格子中输出 第五题: 九数组分数 第六题:牌型种数 第七题: 第一题:方程整数解 方程: a^2 + b^2 + c^2 = 1000 (或参见【图1.jpg】) 这个方程有整数解吗?有:a,b,c=6,8,30 就是一组解。 你能算出另一组合适的解吗? 请填写该解中最小的数字。 注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。 #include <iostream&gt...

qq_18841761的博客 498

灾后重建 解题报告

加时间限制的Floyd

OIER成长之路 661

征战蓝桥 —— 2015年第六届 —— C/C++A组第10题——灾后重建

题目 Pear市一共有N(&lt;=50000)个居民点,居民点之间有M(&lt;=200000)条双向道路相连。这些居民点两两之间都可以通过双向道路到达。 这种情况一直持续到最近,一次严重的地震毁坏了全部M条道路。 震后,Pear打算修复其中一些道路,修理第i条道路需要Pi的时间。不过,Pear并不打算让全部的点连通,而是选择一些标号特殊的点让他们连通。 Pear有Q(&lt;=50000)次询...

Alex 1079

2015年 第六届蓝桥杯大赛个人赛省赛(软件类) C/C++大学A组 题目

第六届蓝桥杯大赛个人赛省赛(软件类) C/C++ 大学A组 考生须知: l  考试开始后,选手首先下载题目,并使用考场现场公布的解压密码解压试题。 l  考试时间为4小时。时间截止后,提交答案无效。 l  在考试强制结束前,选手可以主动结束考试(需要身份验证),结束考试后将无法继续提交或浏览答案。 l  选手可浏览自己已经提交的答案。被浏览的答案允许拷贝。 l  对同一题目,选手可多

王小东大将军的博客 1355

蓝桥杯历年省赛试题汇总 C/C++ A组

A组 省赛 B 组的题目可以在这里查看 → 刷题笔记: 蓝桥杯 题目提交网站:Here 2013 第四届 高斯日记 排它平方数 振兴中华 颠倒的价牌 前缀判断 逆波兰表达式 错误票据 买不到的数目 剪格子 大臣的旅费 2014 第五届 猜年龄 切面条 神奇算式 史丰收速算 锦标赛 扑克序列 蚂蚁感冒 地宫取宝 斐波那契 波动数列 2015 第六届...

橘嘉禾 105

蓝桥杯C/C++A组省赛历年真题题解(2013~2021)

蓝桥杯C/C++A组省赛历年真题目录及题解整理

qq_59700927的博客 4万+

第六届蓝桥杯(2015)-省赛题解_C/C++__大学A组

目录感悟总结一、方程整数解 感悟总结 一、方程整数解 方程: a^2 + b^2 + c^2 = 1000 (或参见【图1.jpg】) 这个方程有整数解吗?有:a,b,c=6,8,30 就是一组解。 你能算出另一组合适的解吗?请填写该解中最小的数字。 注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。 二、星系炸弹 在X星系的广袤空间中漂浮着许多X星人造“炸弹”,用来作为宇宙中的路标。 每个炸弹都可以设定多少天之后爆炸。 比如:阿尔法炸弹2015年1月1日放置,定时为15天,则它在2015

qq_45973802的博客 580

蓝桥杯每日一刷(第三天)

文章目录前言2015a 暴力枚举解方程2015a .灾后重建 (难)最后最后 前言 距离蓝桥杯还剩短短俩个月的时间,最后的号角已经吹响,没有撤退可言! 最后的时间如果要彻底的搞懂比赛所需的算法,很难,但是最后的成绩可能也不是很好,所以我们用真题+解析的形式来做最后的冲刺! 话不多说,开启我们的第三天! 2015a 暴力枚举解方程 方程: a^2 + b^2 + c^2 = 1000 a,b,c都是整数 这个方程有整数解吗?有:a,b,c=6,8,30 就是一组解。 你能算出另一组合适的解吗? 请填写

秋名山码民的技术小屋 893

C/C++ 第六届蓝桥杯大赛个人赛省赛(大学A组) 题解

C/C++ 第六届蓝桥杯大赛个人赛省赛(大学A组) 题解 题目 类型 方程整数解 结果填空 星系炸弹 结果填空 奇妙的数字 结果填空 格子中输出 代码填空 九数组分数 代码填空 牌型种数 结果填空 手链样式 结果填空 饮料换购 程序设计 垒骰子 程序设计 灾后重建 程序设计 1. 方程整数解 本题总分:3分 问题描述 方程: a2 + b2 + c2 = 1000 (或参见下图) 这个方程有整数解吗?有:a,b,c=6,8,30 就是一组解。

陈陈陈Chan的博客 1116
上一篇: 2015蓝桥杯C++A组——垒骰子
下一篇: 2014蓝桥杯C++A组——猜年龄
wxydsq_123
博客等级 码龄8年 2650粉丝 91原创
评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wxydsq_123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值