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

news2024/11/18 23:26:22

10. 灾后重建

Pear市一共有N(<=50000)个居民点,居民点之间有M(<=200000)条双向道路相连。这些居民点两两之间都可以通过双向道路到达。这种情况一直持续到最近,一次严重的地震毁坏了全部M条道路。
震后,Pear打算修复其中一些道路,修理第i条道路需要Pi的时间。不过,Pear并不打算让全部的点连通,而是选择一些标号特殊的点让他们连通。
Pear有Q(<=50000)次询问,每次询问,他会选择所有编号在[l,r]之间,并且 编号 mod K = C 的点,修理一些路使得它们连通。由于所有道路的修理可以同时开工,所以完成修理的时间取决于花费时间最长的一条路,即涉及到的道路中Pi的最大值。

你能帮助Pear计算出每次询问时需要花费的最少时间么?这里询问是独立的,也就是上一个询问里的修理计划并没有付诸行动。

【输入格式】
第一行三个正整数N、M、Q,含义如题面所述。
接下来M行,每行三个正整数Xi、Yi、Pi,表示一条连接Xi和Yi的双向道路,修复需要Pi的时间。可能有自环,可能有重边。1<=Pi<=1000000。
接下来Q行,每行四个正整数Li、Ri、Ki、Ci,表示这次询问的点是[Li,Ri]区间中所有编号Mod Ki=Ci的点。保证参与询问的点至少有两个。

【输出格式】
输出Q行,每行一个正整数表示对应询问的答案。

【样例输入】
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

【数据范围】
对于20%的数据,N,M,Q<=30
对于40%的数据,N,M,Q<=2000
对于100%的数据,N<=50000,M<=2*10^5,Q<=50000. Pi<=10^6.
Li,Ri,Ki均在[1,N]范围内,Ci在[0,对应询问的Ki)范围内。

资源约定:
峰值内存消耗 < 256M
CPU消耗 < 5000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。

这题比较复杂,我们需要分析一下。

首先,每次询问其实都是给出一个特定点集,要求最小化把这些点连通的边权的最大值。
那么,该问题是MST问题的变体 最小生成树资料
进一步地,对于每次询问,最佳方案的边都在原图的最小生成树中,可由反证法证得。
因此,算法的第一部分就是抛弃原图,只留下最小生成树,边数减少到 n − 1 n-1 n1,并且有很多好用的特征。

任选一点使之成为有根树,树上任意两点有且仅有一条简单路径,也即两点分别向上连到LCA 最近公共祖先资料
再考虑,点1点3路径的最大值,其实已包含在点1点2路径和点2点3路径,可以对LCA分类讨论证得。
因此,对于特定点集并不需要两两求LCA,只需要对“相邻”点顺序求过去就行,复杂度由平方降为线性。
原图MST不会变动,可以采用倍增预处理的方法作为算法的第二部分。

本题所取点集与除法取模有关,可以考虑 Big Small 分界,【待补完】 线段树资料

本题从 Big Small 分界出发,但其实到最后并不需要 Big Small 分界,直接建简化线段树的复杂度是没有问题的,也真是有趣。考虑最极端情况,每次询问的 ( k , c ) (k,c) (k,c)均不同,每次都需要重新建树,因为 k k k越小点集越大,且对于每个 k k k c c c各有 k k k种取值,因此建树的总复杂度上限为
T ( n ) = n 1 log ⁡ n 1 + ( n 2 log ⁡ n 2 ) × 2 + ( n 3 log ⁡ n 3 ) × 3 + … T(n) = \frac{n}{1}\log \frac{n}{1} + (\frac{n}{2}\log \frac{n}{2}) \times 2 + (\frac{n}{3}\log \frac{n}{3}) \times 3 + \dots T(n)=1nlog1n+(2nlog2n)×2+(3nlog3n)×3+
= n log ⁡ n 1 + n log ⁡ n 2 + n log ⁡ n 3 + … = n \log \frac{n}{1} + n \log \frac{n}{2} + n \log \frac{n}{3} + \dots =nlog1n+nlog2n+nlog3n+
= Θ ( n ⋅ n ⋅ log ⁡ n ) = \Theta(\sqrt{n} \cdot n \cdot \log n) =Θ(n nlogn)

查询的总复杂度显然是 Θ ( q ⋅ log ⁡ n ) \Theta(q \cdot \log n) Θ(qlogn),两部分都完全没毛病。

不过在线练习系统只给了1s的时限就比较紧,这就必须得套个读入优化才能保证每次都过了,读入量接近百万级(20w*3+5w*4)。

#include <bits/stdc++.h>
using namespace std;

typedef pair<int, int> PII;
const int N = 50010;
const int M = 200010;
const int FN = 16;
vector<PII> G[N];
int dep[N], ans[N];
int fa[N][FN], val[N][FN];
struct Que {
    int x, l, r, k, c;
} que[N];
bool debug = false;

inline void getmax(int& x, int y)
{
    if (y > x)
        x = y;
}

namespace Kruskal {
int p[N], ra[N];
struct Edge {
    int u, v, w;
} eg[M];

int cmp(const Edge& p1, const Edge& p2) { return p1.w < p2.w; }

int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }

int merge(int x, int y)
{
    x = find(x);
    y = find(y);
    if (x == y)
        return 0;
    if (ra[x] > ra[y]) {
        p[y] = x;
    } else {
        if (ra[x] == ra[y])
            ra[y]++;
        p[x] = y;
    }
    return 1;
}

void build(int kn, int km)
{
    int cnt = 0;
    for (int i = 1; i <= kn; i++) {
        p[i] = i;
        ra[i] = 0;
    }
    sort(eg + 1, eg + km + 1, cmp);
    for (int i = 1; i <= km; i++) {
        if (merge(eg[i].u, eg[i].v)) {
            G[eg[i].u].push_back(PII(eg[i].v, eg[i].w));
            G[eg[i].v].push_back(PII(eg[i].u, eg[i].w));
            if (++cnt == kn - 1)
                break;
        }
    }
}
} // namespace Kruskal

class SegTree {
#define lson rt << 1, l, m
#define rson rt << 1 | 1, m + 1, r
public:
    int key[N << 2];
    void build(int a[], int rt, int l, int r)
    {
        if (l == r) {
            key[rt] = a[l];
            return;
        }
        int m = (l + r) >> 1;
        build(a, lson);
        build(a, rson);
        push_up(rt);
    }
    int query(int rt, int l, int r, int L, int R)
    {
        if (L <= l && r <= R) {
            return key[rt];
        }
        int m = (l + r) >> 1;
        int res = 0;
        if (L <= m)
            getmax(res, query(lson, L, R));
        if (m < R)
            getmax(res, query(rson, L, R));
        return res;
    }

private:
    inline void push_up(int rt)
    {
        key[rt] = max(key[rt << 1], key[rt << 1 | 1]);
    }
#undef lson
#undef rson
};
SegTree T;

void dfs(int u, int x)
{
    for (size_t i = 0; i < G[u].size(); i++) {
        int v = G[u][i].first;
        int w = G[u][i].second;
        if (v != x) {
            dep[v] = dep[u] + 1;
            fa[v][0] = u;
            val[v][0] = w;
            dfs(v, u);
        }
    }
}

bool cmpkc(const Que& p, const Que& q)
{
    return p.k < q.k || (p.k == q.k && p.c < q.c);
}

int query(int x, int y)
{
    if (x == 0)
        return 0;
    if (debug)
        printf("------%d %d------\n", x, y);
    if (dep[x] > dep[y])
        swap(x, y);
    int res = 0, di = dep[y] - dep[x];
    for (int k = 0; k < FN; k++) {
        if ((di >> k) & 1) {
            getmax(res, val[y][k]);
            y = fa[y][k];
        }
    }
    if (debug)
        printf("%d %d, %d\n", x, y, res);
    int k = FN - 1;
    while (x != y) {
        while (k > 0 && fa[x][k] == fa[y][k])
            --k;
        getmax(res, val[x][k]);
        getmax(res, val[y][k]);
        x = fa[x][k];
        y = fa[y][k];
        if (debug)
            printf("%d %d, %d\n", x, y, res);
    }
    return res;
}

template <class T>
inline bool read(T& x)
{
    char c;
    int neg = 0;
    if (c = getchar(), c == EOF)
        return false; // EOF
    while (c != '-' && (c < '0' || c > '9'))
        c = getchar();
    if (c == '-')
        neg = 1, c = getchar();
    x = (c - '0');
    while (c = getchar(), c >= '0' && c <= '9')
        x = (x << 3) + (x << 1) + (c - '0');
    if (neg)
        x = -x;
    return true;
}

int main()
{
    int n, m, q;
    read(n);
    read(m);
    read(q);
    {
        using namespace Kruskal;
        for (int i = 1; i <= m; i++) {
            read(eg[i].u);
            read(eg[i].v);
            read(eg[i].w);
        }
        build(n, m);
    } // G is MST
    fa[1][0] = 1;
    dep[1] = 1;
    dfs(1, 0);
    for (int k = 1; k < FN; k++) {
        for (int i = 1; i <= n; i++) {
            fa[i][k] = fa[fa[i][k - 1]][k - 1];
            val[i][k] = max(val[i][k - 1], val[fa[i][k - 1]][k - 1]);
        }
    }
    for (int i = 1; i <= q; i++) {
        read(que[i].l);
        read(que[i].r);
        read(que[i].k);
        read(que[i].c);
        que[i].x = i;
    }
    sort(que + 1, que + q + 1, cmpkc);
    int tmp[N], tlen;
    for (int x = 1; x <= q; x++) {
        int k = que[x].k, c = que[x].c;
        if (k != que[x - 1].k || c != que[x - 1].c) {
            // not same, rebuild segtree
            tlen = 0;
            for (int i = c; i + k <= n; i += k) {
                tmp[++tlen] = query(i, i + k);
            }
            T.build(tmp, 1, 1, tlen);
        }
        ans[que[x].x] = T.query(1, 1, tlen, (que[x].l - c + k - 1) / k + 1, (que[x].r - c) / k);
    }
    for (int i = 1; i <= q; i++) {
        printf("%d\n", ans[i]);
    }
    return 0;
}

评测截图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1032346.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【10个OOM异常的场景以及对应的排查经验】

文章目录 1. 场景描述&#xff1a;内存泄漏2. 场景描述&#xff1a;过多线程3. 场景描述&#xff1a;大量数据查询4. 场景描述&#xff1a;大文件读取5. 场景描述&#xff1a;高并发访问6. 场景描述&#xff1a;大字符串操作7. 场景描述&#xff1a;大数据集合操作8. 场景描述&…

C语言-扫雷游戏的实现

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

反射【Java】

概念&#xff1a;允许对成员变量&#xff0c;成员方法和构造方法的信息进行编程访问 获取class对象 Class.forName("全类名"); //全类名&#xff1a;包名类名 类名.class 对象.getClass(); //有一个名为Goods的类Class clazz1 Class.forName("com.ln1.Goo…

VR赋能红色教育,让爱国主义精神永放光彩

昨天的918防空警报长鸣&#xff0c;人们默哀&#xff0c;可见爱国主义精神长存。为了贯彻落实“把红色资源利用好、红色传统发扬好、红色基因传承好”的指示精神&#xff0c;许多红色景点开始引入VR全景展示技术&#xff0c;为游客提供全方位720度无死角的景区展示体验。 VR全…

【电源专题】什么是充电芯片的Shipping Mode(船运模式)

现在越来越多电子产品小型化,手持化,这样就需要电池来为产品供电。但电池供电造成的另一个难题就是产品的续航能力的强与弱。 如果想提升续航能力,有一种方法是提高电池容量。如果电池体积没有变化的情况下,可能使用了新型材料、高级技术来增加电池容量,但这势必会增加电池…

Webpack设置代码映射,可调试打包后的代码

当我们的代码打包过后再看源码就会变成下面这个样子&#xff1a; 这时候我们就调试不了我们的代码 解决方式&#xff1a; 在webpack.config.js中添加如下代码&#xff1a; module.exports {mode: "development", // 设置打包的模式&#xff1a;production生产模式…

2000-2021年上市公司劳动投资效率测算数据:劳动投资效率、冗余雇佣、雇佣不足(含原始数据和计算代码do文档)

2000-2021 年上市公司劳动投资效率测算数据&#xff1a;劳动投资效率、冗余雇佣、雇佣不足 &#xff08;含计算代码do文档&#xff09; 1、时间&#xff1a;2000-2021 年 2、范围&#xff1a;沪深A 股上市公司 3、指标&#xff1a;code、year、证券代码、货币资金、短期投资…

TexStudio报错 Class: No Found

\classdocument[preprint,review,fleqn,sort&compress,3p]{elsarticle}这里常见导入的类&#xff08;class&#xff09;文件有article.cls&#xff0c;elsarticle.cls&#xff0c;sn-jnl.cls等 一般来说这些文件都应该和我们的源文件document.tex在同一个目录下。如果不在…

Vue复选框批量删除示例

Vue复选框批量删除 通过使用v-model指令绑定单个复选框 例如<input type"checkbox" id"checkbox" v-model"checked"> 而本次我们要做的示例大致是这样的&#xff0c;首先可以增加内容&#xff0c;然后通过勾选来进行单独或者批量删除&…

chk文件怎么恢复?chk文件恢复软件哪个好?

电脑中的每个文件都有其不同的后缀名&#xff0c;如.txt、.png等等&#xff0c;那么你知道.chk后缀的文件是什么吗&#xff1f;下面我们就来一起了解一下吧。 chk文件的含义 chk文件是用户在使用磁盘碎片整理程序后所产生的丢失簇的恢复文件&#xff0c;磁盘中的原文件并没有丢…

0基础学three.js环境搭建(2)

这是0基础学three.js系列中的第二篇&#xff0c;在这篇里面我会带着大家把开发环境搭建起来&#xff0c;关于开发环境&#xff0c;方式很多&#xff0c;如果你没有基础&#xff0c;就跟着我的步骤一步一步来&#xff0c;保你不出错。 首先安装node环境&#xff0c;关于node是干…

操作系统、进程和线程

目录 一、操作系统 二、进程/任务&#xff08;Process/Task&#xff09; 1. 什么是进程/任务 2. 进程控制块抽象&#xff08;PCB Process control Block&#xff09; 3. CPU分配 —— 进程调度&#xff08;Process Scheduling&#xff09; 4. 内存分配 —— 内存管理&…

【Redis】第5讲 Redis的下载并安装

下载Redis中文网https://www.redis.net.cn/ 百度网盘下载&#xff1a; 百度网盘 请输入提取码百度网盘为您提供文件的网络备份、同步和分享服务。空间大、速度快、安全稳固&#xff0c;支持教育网加速&#xff0c;支持手机端。注册使用百度网盘即可享受免费存储空间https://p…

软件测试这些基本类型你知道吗?

【软件测试面试突击班】如何逼自己一周刷完软件测试八股文教程&#xff0c;刷完面试就稳了&#xff0c;你也可以当高薪软件测试工程师&#xff08;自动化测试&#xff09; 关于软件测试的类型&#xff0c;从不同角度来讲&#xff0c;可以分很多种&#xff0c;有时候甚至觉得软件…

深入理解Elasticsearch中的Match Phrase查询

文章目录 摘要Match Phrase查询的原理Match Phrase查询的用法Match Phrase查询的示例代码 Match Phrase查询的注意事项总结 摘要 Elasticsearch是一个功能强大的开源搜索引擎&#xff0c;它提供了丰富的查询功能。其中&#xff0c;Match Phrase查询是一种强大的查询类型&#…

1784_C语言实现常用的复数运算

全部学习汇总&#xff1a; GitHub - GreyZhang/c_basic: little bits of c. 这是最近学习的C语言数据结构的中的案例&#xff0c;但是没有给出具体的实现代码。根据自己的学习水平简单编写了一下&#xff0c;倒是能够计算与输出&#xff0c;但是不知道还有没有什么缺陷。 借用…

C++笔记之文档术语——将可调用对象作为函数参数

C笔记之文档术语——将可调用对象作为函数参数 相关博文&#xff1a;C笔记之函数对象functors与可调用对象 文章目录 C笔记之文档术语——将可调用对象作为函数参数1.在函数参数中传递可调用对象2.‘在参数中传入可调用对象’和‘将可调用对象作为函数参数’哪个描述更加专业…

MyBatis友人帐之使用注解开发

一、利用注解开发 mybatis最初配置信息是基于 XML ,映射语句(SQL)也是定义在 XML 中的。而到MyBatis 3提供了新的基于注解的配置。不幸的是&#xff0c;Java 注解的的表达力和灵活性十分有限。最强大的 MyBatis 映射并不能用注解来构建 sql 类型主要分成 : select () update …

由union引发的Struct占用内存空间和大小端问题的思考

1. 背景 在看Lua源码的时候&#xff0c;很多地方都用到了union&#xff08;共用体或者联合体&#xff09;&#xff0c;在定义lua类型的时候&#xff0c;为了以一个结构来包含所有的数据类型&#xff0c;设计了一个 TValue类型&#xff0c;TValue类型最终关联到 Value类型&#…

番茄小说推文和番茄短剧推广怎么申请授权

番茄小说推文和番茄短剧推广都可以通过“巨量推文”进行授权 番茄小说是一个独立的小说平台&#xff0c;他们在推文市场有推广预算后交给我们达人进行推广&#xff0c;推广完成后可以获得番茄小说的cpa拉新奖励 番茄短剧和番茄小说类似&#xff0c;只是一个是推广短剧的平台一…