洛谷 P3567:[POI 2014] KUR-Couriers ← 主席树

【题目来源】
https://www.luogu.com.cn/problem/P3567

【题目描述】
Byteasar 在卖电脑游戏的 BAJ 公司上班。
BAJ 公司和多家快递公司合作,由这些快递公司将 BAJ 公司销售的游戏送给客户。
Byteasar 正在审查 BAJ 公司与快递公司的合作情况。
他有一份连续的包裹记录,每个包裹都注明了负责配送的快递公司。
他想确认没有任何一家快递公司比其他的具有不公平的优势。
如果在某个时间段内,某家快递公司配送了一半以上的包裹,我们就说它在该时间段内占主导地位。
Byteasar 想要知道在某些特定的时间段内,哪家快递公司占主导地位(如果存在的话)。
来帮 Byteasar 解决这个问题吧!
请编写一个程序,判断在给定时间段内占主导地位的快递公司,或者判断不存在这样的公司。

【输入格式】
第一行包含两个整数 n,m,用一个空格分隔,分别表示 BAJ 公司发货的包裹总数以及需要查询占主导地位的快递公司的时间段数量。
第二行包含 n 个整数 a1,a2,...,an,用单个空格隔开,ai 表示配送第 i 个包裹的快递公司编号(按照配送时间排序)。
接下来的 m 行,每行指定对某个时间段的询问。
每个询问包含两个整数 l 和 r,用一个空格分隔。这意味着需要确定,在第 l 个包裹到第 r 个包裹(包含这两个包裹)的发货期间,占主导地位的快递公司。

【输出格式】
输出 m 行,每行包含一个整数,表示对于每个询问的时间段占主导地位公司的编号,如果不存在这样的公司则输出 0。

【输入样例】
7 5
1 1 3 2 3 4 3
1 3
1 4
3 7
1 7
6 6

【输出样例】
1
0
3
0
4

【数据范围】
对于所有数据,1≤n,m≤5×10^5,1≤ai≤n。

【算法分析】
● 简化题意: 给一个长度为 n 的正整数序列 a。共有 m 组询问,每次询问一个区间 l,r,是否存在一个数在 l,r 中出现的次数严格大于一半。如果存在,输出这个数,否则输出 0。
● 复用"洛谷 P3834 → https://blog.csdn.net/hnjzsyjyj/article/details/169217793"框架,只改 query 里面一点点,不用新知识点。

【算法代码】

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

const int N=5e5+5;
int root[N],a[N],tot;
vector<int> v;

struct Node {
    int L,R,cnt;
} tr[N*40];

int getid(int x) {
    return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}

int build(int le,int ri) {
    int p=++tot;
    if(le==ri) return p;
    int mid=(le+ri)/2;
    tr[p].L=build(le,mid);
    tr[p].R=build(mid+1,ri);
    return p;
}

int update(int pre,int le,int ri,int x) {
    int p=++tot;
    tr[p]=tr[pre];
    if(le==ri) {
        tr[p].cnt++;
        return p;
    }
    int mid=(le+ri)/2;
    if(x<=mid) tr[p].L=update(tr[pre].L,le,mid,x);
    else tr[p].R=update(tr[pre].R,mid+1,ri,x);
    tr[p].cnt=tr[tr[p].L].cnt+tr[tr[p].R].cnt;
    return p;
}

int query(int u,int v,int le,int ri,int k) {
    if(le==ri) return le;
    int mid=(le+ri)/2;
    int leftcnt=tr[tr[v].L].cnt-tr[tr[u].L].cnt;
    int rightcnt=tr[tr[v].R].cnt-tr[tr[u].R].cnt;
    if(leftcnt>k) return query(tr[u].L,tr[v].L,le,mid,k);
    if(rightcnt>k) return query(tr[u].R,tr[v].R,mid+1,ri,k);
    return 0;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n,m;
    cin>>n>>m;
    for(int i=1; i<=n; i++) {
        cin>>a[i];
        v.push_back(a[i]);
    }
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());

    int len=v.size();
    root[0]=build(1,len);
    for(int i=1; i<=n; i++) {
        root[i]=update(root[i-1],1,len,getid(a[i]));
    }

    while(m--) {
        int le,ri;
        cin>>le>>ri;
        int k=(ri-le+1)/2;
        int id=query(root[le-1],root[ri],1,len,k);
        if(id) cout<<v[id-1]<<"\n";
        else cout<<"0\n";
    }
    return 0;
}

/*
in:
7 5
1 1 3 2 3 4 3
1 3
1 4
3 7
1 7
6 6

out:
1
0
3
0
4
*/

【参考文献】
https://blog.csdn.net/hnjzsyjyj/article/details/169217793

相关推荐
alexwang2113 个月前
HDU 4348 详细题解
c++·算法·题解·hdu·主席树·可持久化数据结构·可持久化线段树
Ayanami_Reii10 个月前
区间不同数的个数-树状数组/线段树/莫队/主席树
数据结构·c++·算法·线段树·树状数组·主席树·莫队
Ayanami_Reii1 年前
详解Splay平衡树
数据结构·算法·线段树·主席树·持久化线段树
Ayanami_Reii1 年前
进阶数据结构应用-SPOJ 3267 D-query
数据结构·算法·线段树·主席树·持久化线段树
Assassin's Creed2 年前
2024江苏省赛E. Divide
c语言·数据结构·c++·算法·acm·主席树
rgw20102 年前
P10789 [NOI2024] 登山
数据结构·动态规划·树上倍增·主席树·树链剖分·前缀优化
邪神与厨二病3 年前
HUAWEI Programming Contest 2024(AtCoder Beginner Contest 342)(A,B,C,D,E,F,G)
数据结构·算法·华为·线段树·动态规划·dijkstra·主席树