[BZOJ3524][Poi2014]Couriers

[Poi2014]Couriers

Description
给一个长度为n的序列a。1≤a[i]≤n。
m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2。如果存在,输出这个数,否则输出0。
Input
第一行两个数n,m。
第二行n个数,a[i]。
接下来m行,每行两个数l,r,表示询问[l,r]这个区间。
Output
m行,每行对应一个答案。
Sample Input
7 5
1 1 3 2 3 4 3
1 3
1 4
3 7
1 7
6 6
Sample Output
1
0
3
0
4
HINT
【数据范围】
n,m≤500000
Source
By Dzy

Solution :
可持久化线段树
对于每一个位置i,维护一棵权值线段树,保留1~i位置上所有数的信息。

Code :

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

#define rep(i, l, r) for (int i = (l); i <= (r); i++)

template<typename T> inline void read(T &x){
    x = 0; T f = 1; char ch = getchar();
    while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
    while (isdigit(ch))  {x = x * 10 + ch - '0'; ch = getchar();}
    x *= f;
}

const int N = 500000 + 10;
int
    root[N], lc[N * 20], rc[N * 20], sum[N * 20];
int
    n, m, a[N], SZ;
inline void modify(int l, int r, int last, int &now, int pos){
    now = ++SZ;
    sum[now] = sum[last] + 1;
    if (l == r) return;
    int mid = l+r >> 1;
    if (pos <= mid){
        rc[now] = rc[last]; 
        modify(l, mid, lc[last], lc[now], pos);
    }else{
        lc[now] = lc[last];
        modify(mid+1, r, rc[last], rc[now], pos);
    }
}

inline void query(int l, int r, int L, int R, int p){
    if (l == r){
        printf("%d\n", sum[R] - sum[L] > p ? l : 0); return;
    }
    int mid = l+r >> 1;
    if (sum[lc[R]] - sum[lc[L]] > sum[rc[R]] - sum[rc[L]]) query(l, mid, lc[L], lc[R], p);
    else query(mid+1, r, rc[L], rc[R], p);
}

int main(){
    read(n); read(m);
    rep(i, 1, n) read(a[i]);
    rep(i, 1, n) modify(1, n, root[i-1], root[i], a[i]);
    rep(i, 1, m){
        int l, r; read(l); read(r); if (l > r) swap(l, r);
        query(1, n, root[l-1], root[r], (r-l+1)/2);
    }
    return 0;    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值