BZOJ 4241: 历史研究

Description

IOI国历史研究的第一人——JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记。JOI教授为了通过这份日记来研究古代IOI国的生活,开始着手调查日记中记载的事件。
日记中记录了连续N天发生的时间,大约每天发生一件。
事件有种类之分。第i天(1<=i<=N)发生的事件的种类用一个整数Xi表示,Xi越大,事件的规模就越大。
JOI教授决定用如下的方法分析这些日记:
1. 选择日记中连续的一些天作为分析的时间段
2. 事件种类t的重要度为t*(这段时间内重要度为t的事件数)
3. 计算出所有事件种类的重要度,输出其中的最大值
现在你被要求制作一个帮助教授分析的程序,每次给出分析的区间,你需要输出重要度的最大值。

Input

第一行两个空格分隔的整数N和Q,表示日记一共记录了N天,询问有Q次。
接下来一行N个空格分隔的整数X1…XN,Xi表示第i天发生的事件的种类
接下来Q行,第i行(1<=i<=Q)有两个空格分隔整数Ai和Bi,表示第i次询问的区间为[Ai,Bi]。

Output

输出Q行,第i行(1<=i<=Q)一个整数,表示第i次询问的最大重要度

Sample Input

5 5

9 8 7 8 9

1 2

3 4

4 4

1 4

2 4

Sample Output

9

8

8

16

16

HINT

1<=N<=10^5

1<=Q<=10^5

1<=Xi<=10^9 (1<=i<=N)

分析

其实就是一道分块的模板题//
但是打挂了,导致我调了好久。。

代码

#include <bits/stdc++.h>

#define N 100010
#define ll long long

int num[N],hash[N];
int cnt[N];

int sum[1000][N];

ll ans[1000][1000];

int tot;
int n,m;

ll t;

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

void Hash()
{
    std::sort(num + 1, num + n + 1);
    int len = std::unique(num + 1, num + n + 1) - num - 1;
    for (int i = 1; i <= n; i++)
        hash[i] = std::lower_bound(num + 1, num + len + 1, hash[i]) - num;
}

void preWork()
{
    tot = floor(sqrt(n)) + 1;
    for (int i = 1; i <= (n - 1) / tot + 1; i++)
    {
        t = 0;
        for (int j = (i - 1) * tot + 1; j <= n; j++)
        {
            cnt[hash[j]]++;
            t = std::max(t, (ll)cnt[hash[j]] * num[hash[j]]);
            ans[i][(j - 1) / tot + 1] = t;
        }
        for (int j = (i - 1) * tot + 1; j <= n; j++)
            cnt[hash[j]]--;
    }
    for (int i = 1; i <= (n - 1) / tot + 1; i++)
    {
        for (int j = 1; j <= n; j++)
            sum[i][j] = sum[i - 1][j];
        for (int j = (i - 1) * tot + 1; j <= std::min(i * tot, n); j++)
            sum[i][hash[j]]++;
    }
}

ll query(int x,int y)
{
    int l = (x - 1) / tot + 1, r = (y - 1) / tot + 1;
    if (l == r)
    {
        t = 0;
        for (int i = x; i <= y; i++)
        {
            cnt[hash[i]]++;
            t = std::max(t, (ll)cnt[hash[i]] * num[hash[i]]);
        }
        for (int i = x; i <= y; i++)
            cnt[hash[i]]--;
        return t;
    }
    t = 0;
    if (l + 1 < r)
        t = ans[l + 1][r - 1];
    for (int i = x; i <= l * tot; i++)
        cnt[hash[i]]++;
    for (int i = (r - 1) * tot + 1; i <= y; i++)
        cnt[hash[i]]++;
    for (int i = x; i <= l * tot; i++)
    {
        if (!cnt[hash[i]])
            continue;
        ll x = sum[r - 1][hash[i]] - sum[l][hash[i]] + cnt[hash[i]];
        x = (ll)x * num[hash[i]];
        t = std::max(t,x);
        cnt[hash[i]] = 0;
    }
    for (int i = (r - 1) * tot + 1; i <= y; i++)
    {
        if (!cnt[hash[i]])
            continue;
        ll x = sum[r - 1][hash[i]] - sum[l][hash[i]] + cnt[hash[i]];
        x = (ll)x * num[hash[i]];
        t = std::max(t,x);
        cnt[hash[i]] = 0;
    }
    return t;
}

int main()
{
    n = read(), m =read();
    for (int i = 1; i <= n; i++)
        num[i] = read(), hash[i] = num[i];
    Hash();
    preWork();
    while (m--)
    {
        int x,y;
        x = read(), y = read();
        printf("%lld\n",query(x,y));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值