首页 > 其他分享 >P8626 [蓝桥杯 2015 省 A] 灾后重建

P8626 [蓝桥杯 2015 省 A] 灾后重建

时间:2024-03-18 23:13:17浏览次数:24  
标签:return int res 蓝桥 other lca 2015 const P8626

根号分治之类的思路分析这里就不讲了,主要关注代码细节:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <string>
#include <cmath>
#define For(i, j, n) for (int i = j; i <= n; ++i)
using namespace std;

const int N = 50005, M = 2e5 + 5;

int n, m, q;

inline int read()
{
    int x = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9')
        ch = getchar();
    while (ch >= '0' && ch <= '9')
        x = x * 10 + ch - '0', ch = getchar();
    return x;
}

// 最小生成树 并查集
int fa[N];
inline int find(int x)
{
    return x == fa[x] ? x : (fa[x] = find(fa[x]));
}

struct StrForEdge
{
    int _from, _to, w;
    bool operator<(const StrForEdge &_other) const
    {
        return w < _other.w;
    }
} Edge[M * 2];

// 树边需要的一些数据成员
typedef pair<int, int> PII;
vector<PII> tree_edges[N];
// 连边
void on_tree_connect(int a, int b, int w)
{
    tree_edges[a].push_back({b, w});
    tree_edges[b].push_back({a, w});
}

void init_tree()
{
    // 初始化并查集
    for (int i = 1; i <= n; i++)
        fa[i] = i;

    int tree_cnt = 0;
    for (int i = 1; i <= m; i++)
    {
        int a = Edge[i]._from, b = Edge[i]._to;
        int pa = find(a), pb = find(b);
        if (pa != pb)
        {
            on_tree_connect(a, b, Edge[i].w);
            fa[pa] = pb;
            if (++tree_cnt == n - 1)
                return;
        }
    }
}

// 最小生成树
int lca_fa[N][17], maxw[N][17], depth[N];

void dfs_lca(int now, int Father)
{
    for (PII edge_on_tree : tree_edges[now])
    {
        int v = edge_on_tree.first, w = edge_on_tree.second;
        if (v == Father)
            continue;
        depth[v] = depth[now] + 1;
        lca_fa[v][0] = now;
        maxw[v][0] = w;
        for (int i = 1; i <= 16; i++)
        {
            lca_fa[v][i] = lca_fa[lca_fa[v][i - 1]][i - 1];
            maxw[v][i] = max(maxw[v][i - 1], maxw[lca_fa[v][i - 1]][i - 1]);
        }
        dfs_lca(v, now);
    }
}

int link_on_tree(int a, int b)
{
    int res = -1;
    if (depth[a] < depth[b])
        swap(a, b);
    int d_of_depth = depth[a] - depth[b];
    for (int i = d_of_depth, Base = 0; i > 0; i >>= 1, Base++)
    {
        if (i & 1)
        {
            res = max(res, maxw[a][Base]);
            a = lca_fa[a][Base];
        }
    }
    if (a == b)
        return res;
    for (int i = 16; i >= 0; i--)
        if (lca_fa[a][i] != lca_fa[b][i])
        {
            res = max(res, maxw[a][i]);
            a = lca_fa[a][i];
            res = max(res, maxw[b][i]);
            b = lca_fa[b][i];
        }
    res = max(res, max(maxw[a][0], maxw[b][0]));
    return res;
}

void init_lca()
{
    // 以一号节点为根
    depth[1] = 1;
    dfs_lca(1, 0);
}

// 把询问离线,分辨建立线段树

int ans[N];
struct StruForSegTree
{
    int l, r, maxx;
} SegTree[N * 4];
// 线段树的元数据
int DisofSegTree[N];

struct StruForQuery
{
    int l, r, k, c, id;
    bool operator<(const StruForQuery &_other) const
    {
        if (k != _other.k)
            return k < _other.k;
        return c < _other.c;
    }

} Q[N];

void BuildSegTree(int now, int l, int r)
{
    SegTree[now] = {l, r, 0};
    if (l == r)
    {
        SegTree[now].maxx = DisofSegTree[l];
        return;
    }
    int mid = (l + r) >> 1;
    int lson = now << 1, rson = now << 1 | 1;
    BuildSegTree(lson, l, mid);
    BuildSegTree(rson, mid + 1, r);
    SegTree[now].maxx = max(SegTree[lson].maxx, SegTree[rson].maxx);
}

void SmallInit(StruForQuery qnow)
{
    int L = 0, R = n, DataCnt = 0;
    for (int i = L / qnow.k * qnow.k + qnow.c; i + qnow.k <= R; i += qnow.k)
    {
        if (i < L)
            continue;
        DisofSegTree[++DataCnt] = link_on_tree(i, i + qnow.k);
    }
    BuildSegTree(1, 1, DataCnt);
}

int SegTreeQuery(int now, int l, int r)
{
    if (SegTree[now].l >= l && SegTree[now].r <= r)
        return SegTree[now].maxx;
    int mid = (SegTree[now].l + SegTree[now].r) >> 1;
    int res = -1;
    if (l <= mid)
        res = SegTreeQuery(now << 1, l, r);
    if (r > mid)
        res = max(res, SegTreeQuery(now << 1 | 1, l, r));
    return res;
}

int SmallQuery(StruForQuery qnow, bool has_changed)
{
    if (has_changed)
        SmallInit(qnow);
    int L = qnow.l, R = qnow.r;
    int k = qnow.k, c = qnow.c;
    int _offset = 1 + ((L - c) % k != 0);
    int l_to_query = (L - c) / k + _offset;
    if (L <= c)
        l_to_query = 1;
    int r_to_query = (R - c) / k;
    return SegTreeQuery(1, l_to_query, r_to_query);
}

int BigQuery(StruForQuery qnow)
{
    int L = qnow.l, R = qnow.r, ans = -1;
    for (int i = L / qnow.k * qnow.k + qnow.c; i + qnow.k <= R; i += qnow.k)
    {
        if (i < L)
            continue;
        ans = max(ans, link_on_tree(i, i + qnow.k));
    }
    return ans;
}

int main()
{
    n = read();
    m = read();
    q = read();
    int tmpa, tmpb, tmpc;
    for (int i = 1; i <= m; i++)
    {
        tmpa = read();
        tmpb = read();
        tmpc = read();
        Edge[i] = {tmpa, tmpb, tmpc};
    }
    sort(Edge + 1, Edge + m + 1);
    init_tree();
    init_lca();
    int ql, qr, qk, qc;
    int Threshold = min(n / 3, 110);
    for (int i = 1; i <= q; i++)
    {
        ql = read();
        qr = read();
        qk = read();
        qc = read();
        Q[i] = {ql, qr, qk, qc, i};
    }
    sort(Q + 1, Q + q + 1);
    int know = 0, kc = 0;
    for (int i = 1; i <= q; i++)
    {
        if (Q[i].k > Threshold)
        {
            ans[Q[i].id] = BigQuery(Q[i]);
            continue;
        }
        bool has_changed = false;
        if (know != Q[i].k)
            know = Q[i].k, has_changed = true;
        if (kc != Q[i].c)
            kc = Q[i].c, has_changed = true;
        ans[Q[i].id] = SmallQuery(Q[i], has_changed);
    }
    for (int i = 1; i <= q; i++)
        printf("%d\n", ans[i]);
    return 0;
}

为什么一开始会超时:

确实,通过重定义小于运算符来对查询进行排序,理论上会将具有相同`k`和`c`值的查询放在一起。这是因为你的排序策略首先考虑`k`的值,然后是`c`的值。这样做的目的是为了将具有相同参数的查询分组,以便可以一次性处理这些查询,减少重复的初始化操作。你提供的代码片段是:

```cpp
bool operator < (const StruForQuery &_other)const
{
return k < _other.k;
if(k == _other.k)
return c < _other.c;
}
```

然而,上面的重载`operator<`实际上有一个逻辑错误。如果`k < _other.k`为`true`,那么比较就在这里结束,这是正确的。但是,如果`k == _other.k`,那么你希望进一步比较`c`的值。然而,由于`return k < _other.k;`这行代码的存在,当`k`等于`_other.k`时,函数就会结束,后面的`if(k == _other.k)`永远不会执行。

正确的写法应该是:

```cpp
bool operator < (const StruForQuery &_other)const
{
if(k != _other.k) return k < _other.k;
return c < _other.c;
}
```
或者更简洁的形式:

```cpp
bool operator < (const StruForQuery &_other)const
{
return k == _other.k ? c < _other.c : k < _other.k;
}
```

这样就可以确保当`k`相等时,会根据`c`的值进行排序,确保具有相同`k`和`c`的查询会被放在一起。

如果你在实现中已经正确地排序了查询,那么每次遇到不同的`(k, c)`组合时确实应该只初始化一次。如果出现重复初始化的情况,可能需要进一步检查逻辑,确认是不是每个组合确实只处理了一次,或者是不是排序后的查询确实如你所期望的那样正确分组。此外,确认`SmallInit`调用和相关处理是否被正确地限制在每个独特的`(k, c)`组合上。

总之,正确实现和应用排序逻辑是关键,这将确保查询按照期望的方式被组织和处理,从而避免不必要的重复操作。

关键就在于直接return了,如果k!=_other.k,那么就会直接return false,但是后面有关c的判断并不会被执行。

标签:return,int,res,蓝桥,other,lca,2015,const,P8626
From: https://www.cnblogs.com/smartljy/p/18081730

相关文章

  • 蓝桥杯day4刷题日记
    P8605[蓝桥杯2013国AC]网络寻路思路来源于https://www.luogu.com.cn/article/iat8irsf#include<iostream>usingnamespacestd;intn,m;intq[10010];intv[100010],u[100010];longlongres;intmain(){ cin>>n>>m; for(inti=0;i<m;i++) { cin......
  • 蓝桥杯——344图书管理员
      法一使用取模运算对于每本书的图书编码(bookCode),我们需要判断其是否以读者的需求码结尾。首先,将需求码的长度作为指数,使用Math.pow(10,demandLength)来得到一个以需求码长度为指数的基数。然后,将书的图书编码与这个基数进行取模运算,即bookCode%Math.pow(10,demandLe......
  • 2023年蓝桥杯省赛——幸运数字
    目录题目链接:0幸运数字-蓝桥云课(lanqiao.cn)解法思路高级思路总结题目链接:0幸运数字-蓝桥云课(lanqiao.cn)解法首先是我写了差不多一个小时的解法,裂开了,为什么我如此废物思路        寻找第2023个在二进制、八进制、十进制和十六进制表示下都为哈......
  • 2023年蓝桥杯模拟省赛——列名
    目录题目链接:2.列名-蓝桥云课(lanqiao.cn)思路高级思路:进制转换难点一难点二难点三总结题目链接:2.列名-蓝桥云课(lanqiao.cn)思路先来看我的暴力的思路吧主要有以下步骤:初始化一个长度为3的数组res用于存放结果,并且定义一个变量 p 表示目前数组中的......
  • 蓝桥杯单片机PCF8951数模转换测光敏电阻和滑动变阻器
    无论怎么调试,数码管只显示000,让人非常苦恼。下面是代码,请各位大佬指点>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>这是main函数/*头文件声明区*/#include<STC15F2K60S2.H>......
  • 【洛谷 P8661】[蓝桥杯 2018 省 B] 日志统计 题解(滑动窗口+优先队列+双端队列+集合)
    [蓝桥杯2018省B]日志统计题目描述小明维护着一个程序员论坛。现在他收集了一份“点赞”日志,日志共有NNN行。其中每一行的格式是tsid,表示在......
  • 【洛谷 P8602】[蓝桥杯 2013 省 A] 大臣的旅费 题解(图论+深度优先搜索+树的直径+链式
    [蓝桥杯2013省A]大臣的旅费题目描述很久以前,T王国空前繁荣。为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。同......
  • 蓝桥杯单片机STC15F2K60S2第十三届省赛代码详细讲解(附完整代码)
     一、前言            在蓝桥杯单片机的比赛当中,很多传感器都是会经常使用到的,比如说DS18B20和DS1302等,都是会经常用到的,所以我们要把这些传感器都学会一下。在省十三的蓝桥杯单片机题目中,我自己也写了一下这个代码,可能有些地方会有点问题,但是大致的功能还是能......
  • 蓝桥杯算法集训 - Week 2:双指针、归并排序、多路归并
    蓝桥杯算法集训-Week2本系列随笔用于整理AcWing题单——《蓝桥杯集训·每日一题2024》的系列题型及其对应的算法模板。一、双指针Ⅰ、代码模板常见问题分类:(1)对于一个序列,用两个指针维护一段区间(2)对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作f......
  • 会议室预约系统优化(蓝桥杯)
    文章目录会议室预约系统优化问题描述差分会议室预约系统优化问题描述假设你是一家大型企业的IT工程师,企业内有n个会议室,每天都有多个部门预约会议室进行会议。你的任务是优化现有的会议室预约系统。你需要设计一个程序来支持以下两种操作:预约会议室:给定一......