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万+

直流电机双闭环调速系统MATLAB仿真

Chopper-Fed DC Motor Drive This example shows a Chopper-Fed DC Motor Drive. Description The DC motor is fed by the DC source through a chopper which consists of GTO thyristor and free-wheeling diode ...

飞行动力的博客 2万+

蓝桥杯试题——灾后重建

蓝桥杯试题——灾后重建 #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

【TM1640】STM32 TM1640芯片驱动程序

以下为.h文件: #ifndef __TM1640_H__ #define __TM1640_H__ #include "stm32f10x.h" #define ADDR_START1640 0XC0 #define DSP1640_DIS 0 #define DSP1640_ENB 1 /* 控制显示 ...

cxw312864660的博客 1万+

Vivado2019.1 ZYNQ7020无Uart SDK调试打印调试信息xil_printf

Vivado2019.1 ZYNQ7020无Uart SDK调试打印调试信息xil_printf

泛红尘的博客 2997

灾后重建(C++,Floyd)

floyd算法的变形应用

m0_74036684的博客 571

高效管理Node.js版本与pnpm安装全攻略

本文提供了一套高效管理Node.js版本与pnpm安装的完整攻略。针对开发中常见的版本冲突和磁盘空间问题,详细介绍了如何在Windows和Ubuntu系统上安装并配置pnpm,并重点讲解了如何利用其内置的`pnpm env`命令进行Node.js版本管理,实现一站式环境管理,提升开发效率。

weixin_28840591的博客 313

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

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

——Light! 1728

强化学习实战——OpenAI Gym环境配置+实战演示(win10)

遇到问题:无法安装pickle5原因是:python3.8与该包不兼容,必须降python3.7的版本。

LZL2020LZL的博客 4899

学Simulink--基于新能源与储能系统的场景实例:压缩空气储能(CAES)系统热力学建模

本文介绍了使用Simulink对压缩空气储能(CAES)系统进行热力学建模的详细流程。重点讲解了系统各模块的设计方法,包括压缩机、储气装置、膨胀机和热交换器等核心组件的参数设置与计算模型。文章还提供了控制策略设计和仿真运行的具体步骤,通过建立MATLAB函数计算关键参数变化,并分析了系统性能评估指标。该建模方法可用于验证CAES系统的设计有效性,并为优化储能效率提供技术参考。全文采用模块化设计思路,为新能源与储能系统的仿真研究提供了实用案例。

xiaoheshang_123的博客 298

蓝桥杯——灾后重建

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

志远的博客 2251

33、嵌入式系统中的内存操作与实时操作系统

本博客详细探讨了嵌入式系统中的内存操作和实时操作系统(RTOS)的基本原理及应用。内容涵盖C、C++和MicroPython三种语言下的SDRAM读写示例,并结合机器人真空吸尘器的实际应用说明内存的使用场景。此外,还介绍了RTOS的核心概念、组件及其工作机制,包括任务、事件、互斥锁、信号量、队列等,并以FreeRTOS和Mbed OS为例展示了RTOS的配置与使用方法。最后,通过常见问题和实践项目加深对嵌入式系统开发的理解。

zz67890的博客 145

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

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

Willen_的博客 1348

“探索thumbdata4文件的奥秘:编程中的神秘存在“

综上所述,thumbdata4文件在编程中是一个常见的存在,与图库应用程序和图片浏览器密切相关。通过使用适当的库和工具,我们可以读取和处理thumbdata4文件中的缩略图数据,以提供更好的用户体验。我们首先读取8字节的块头,其中包含了下一个缩略图块的大小。你可以根据自己的需求来定义对块数据的处理方式,例如将其保存为图像文件或进行其他的分析操作。thumbdata4文件通常以二进制格式存储,其中包含着设备上浏览过的图片的缩略图。因此,你可能需要根据具体的thumbdata4文件结构进行适当的解析和处理。

JieLun_C的博客 792

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

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

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

KI的博客 8万+

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

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

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

戎码一生的博客 6273

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

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、付费专栏及课程。

余额充值