Luogu P3567 [POI2014]KUR-Couriers

Posted maowuyou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu P3567 [POI2014]KUR-Couriers相关的知识,希望对你有一定的参考价值。

说一道 POI 的 水题 

题 目 链 接     : https://www.luogu.com.cn/problem/P3567#submit

翻 译 中 题 意 已 经 很 简 洁 了 ,这 里 不 做 多 余 的 简 化。

题 目 很 明 显 是 一 道 数 据 结 构 题 。

对 于 这 一 类 题 型 ,通 常 要 考 虑 将 原 问 题 的 转 化 。

这 一 点 其 实 是 很 重 要 的 。毕 竟 不 是 所 有 题 都 是 板 子 题 。

对 于 这 个 问 题 :每 次 询 问 一 个 区 间 内 有 没 有 一 个 数 出 现 次 数 超 过 一 半 。

我 们 考 虑 :假 设 存 在 一 个 区 间 ,其 间 存 在 一 个 满 足 题 意 的 数 。

注 意 :对 于 每 个 区 间 ,最 多 仅 存 在 一 个 数 满 足 题 意 。这 一 点 相 信 很 容 易 理 解 。

我 们 再 考 虑 : 在 区 间 内 的 数 中 ,哪 个 数 是 有 可 能 满 足 题 意 的 ?

答 案 也 很 显 然 。

既 然 出 现 次 数 超 过 一 半 ,区 间 中 自 然 不 存 在 出 现 次 数 比 它 多 的 数。

即 假 设 一 个 数 符 合 题 意 ,他 定 然 同 时 也 是 区 间 众 数 。

由 于 这 个 题 目 不 带 修 改 。 我 们 考 虑 使 用 logn 的 主 席 树 。

预 处 理 是 很 标 准 的 权 值 主 席 树 。如 果 你 不 会 ,或 不 是 很 理 解 建 议 参 照  我所看见的比较好的主席树入门

每 次 查 询 ,在 树 上 往 大 的 儿 子 走 ,因 为 只 有 大 的 儿 子 ,才 可 能 存 在 超 过 一 半 的 叶 节 点 。

最 后 判 断 一 下 ,到 达 的 叶 子 节 点 的 权 值 是 否 大 于 区 间 一 半 长 度 一 半 就 行 了。 

详 见 代 码 

 

#include<bits/stdc++.h>
#define MAXN 15000005
#define INF 1000000
using namespace std;
namespace A
{
    int tot;
    int L[MAXN],R[MAXN],val[MAXN];
    int build(int l,int r,int x,int last)
    {
        int rt=++tot;
        L[rt]=L[last];
        R[rt]=R[last];
        val[rt]=val[last];
        if (l==r)
        {
            val[rt]++;
            return rt;
        }
        int mid=(l+r)>>1;
        if (x<=mid) L[rt]=build(l,mid,x,L[last]);
        else R[rt]=build(mid+1,r,x,R[last]);
        val[rt]=val[L[rt]]+val[R[rt]];
        return rt;
    }
    int ask(int rt1,int rt2,int l,int r,int x)
    {
        if (l==r) return l;
        int mid=(l+r)>>1;
        if (val[L[rt2]]-val[L[rt1]]>=x) return ask(L[rt1],L[rt2],l,mid,x);
        if (val[R[rt2]]-val[R[rt1]]>=x) return ask(R[rt1],R[rt2],mid+1,r,x);
        return 0;
    }
}
int n,m,rt[MAXN];
int main()
{
    scanf("%d %d",&n,&m);
    for (int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        rt[i]=A::build(1,INF,x,rt[i-1]);
    }
    for (int i=1;i<=m;i++)
    {
        int l,r;
        scanf("%d %d",&l,&r);
        printf("%d
",A::ask(rt[l-1],rt[r],1,INF,(r-l+1)/2+1));
    }
    return 0;
}

 

 

 

 

以上是关于Luogu P3567 [POI2014]KUR-Couriers的主要内容,如果未能解决你的问题,请参考以下文章

luogu P3567 [POI2014] Couriers

luogu P3567 [POI2014]KUR-Couriers |莫队+随机化

luogu P3567 [POI2014]KUR-Couriers |莫队+随机化

luogu P3567 [POI2014]KUR-Couriers

P3567 [POI2014]KUR-Couriers

P3567 [POI2014]KUR-Couriers