【bzoj4241】历史研究

  这题也是坑了好久>_<
  之前whx带我刷JOI的时候本来应该要做的。。。可是太懒没有写。。。
  区间询问加权众数。
分块,预处理出块和块之间的答案,记录到第i个块数字x出现了多少次。然后查询的时候和普通众数基本一样,就是乘了个权值而已。
要离散化。
时间复杂度 O(nlogn+mn)
昨晚写的常数太烂了。。。用了struct,数组开大了,狂M
然后卡了卡空间,狂RE doge
然后查了很久发现有个边界写的有点问题
改完之后就无限TLE辣QAQ
电脑课花了20min来rewrite结果就A掉了smg。。。。

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a,_=b;i<=_;i++)
#define per(i,a,b) for(int i=a,_=b;i>=_;i--)
#define maxn 100007
#define maxb 331

inline int rd() {
    char c = getchar();
    while (!isdigit(c)) c = getchar() ; int x = c - '0';
    while (isdigit(c = getchar())) x = x * 10 + c - '0';
    return x;
}

typedef long long ll;

inline void upmax(ll&a , ll b) { if (a < b) a = b ; }

typedef int arr_int[maxn];
typedef ll  arr_ll [maxn];
typedef int blk_int[maxb];
typedef ll  blk_ll [maxb];

int n , m , all , len , tot;
arr_int h , a , cnt , belong;
blk_ll  ans[maxb];
arr_int sum[maxb] , st , ed;

void input() {
    n = rd() , m = rd();
    rep (i , 1 , n) h[i] = a[i] = rd();
    sort(h + 1 , h + n + 1);
    all = unique(h + 1 , h + n + 1) - h - 1;
    rep (i , 1 , n) a[i] = lower_bound(h + 1 , h + all + 1 , a[i]) - h;
}

void init_block() {
    len = (int) sqrt(n + 0.5);
    rep (i , 1 , n)
        belong[i] = (i - 1) / len + 1;
    tot = belong[n];
    rep (i , 1 , tot)
        st[i] = (i - 1) * len + 1 , ed[i] = i * len;
    ed[tot] = n;
    rep (i , 1 , n)
        sum[belong[i]][a[i]] ++;
    rep (i , 1 , tot)
        rep(x , 1 , all)
            sum[i][x] += sum[i - 1][x];
    rep (i , 1 , tot) {
        rep (j , st[i] , n) cnt[a[j]] = 0;
        ll mx = 0;
        rep (j , st[i] , n) {
            int x = a[j];
            cnt[x] ++;
            upmax(mx , (ll) cnt[x] * h[x]);
            ans[i][belong[j]] = mx;
        }
    }
}

void query(int l , int r) {
    ll mx = 0;
    int L = belong[l] , R = belong[r];
    if (L == R) {
        rep (i , l , r) cnt[a[i]] ++ ;
        rep (i , l , r) {
            int x = a[i];
            if (!cnt[x]) continue;
            upmax(mx , (ll) cnt[x] * h[x]);
            cnt[x] = 0;
        }
    } else {
        if (L + 1 < R)
            mx = ans[L + 1][R - 1];
        rep (i , l , ed[L]) cnt[a[i]] ++ ;
        rep (i , st[R] , r) cnt[a[i]] ++ ;
        rep (i , l , ed[L]) {
            int x = a[i];
            if (!cnt[x]) continue;
            ll ts = sum[R - 1][x] - sum[L][x] + cnt[x];
            ts *= h[x] , cnt[x] = 0;
            upmax(mx , ts);
        }
        rep (i , st[R] , r) {
            int x = a[i];
            if (!cnt[x]) continue;
            ll ts = sum[R - 1][x] - sum[L][x] + cnt[x];
            ts *= h[x] , cnt[x] = 0;
            upmax(mx , ts);
        }
    }
    printf("%lld\n" , mx);
}

void solve() {
    init_block();
    memset(cnt , 0 , sizeof cnt);
    rep (i , 1 , m) {
        int l = rd() , r = rd();
        query(l , r);
    }
}

int main() {
    #ifndef ONLINE_JUDGE
        freopen("data.txt" , "r" , stdin);
        freopen("data.out" , "w" , stdout);
    #endif
    input();
    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值