hdu4638-Group(莫队算法)

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4638

题目原文:

Group

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3742    Accepted Submission(s): 1826


 

Problem Description

There are n men ,every man has an ID(1..n).their ID is unique. Whose ID is i and i-1 are friends, Whose ID is i and i+1 are friends. These n men stand in line. Now we select an interval of men to make some group. K men in a group can create K*K value. The value of an interval is sum of these value of groups. The people of same group's id must be continuous. Now we chose an interval of men and want to know there should be how many groups so the value of interval is max.

 

 

Input

First line is T indicate the case number.
For each case first line is n, m(1<=n ,m<=100000) indicate there are n men and m query.
Then a line have n number indicate the ID of men from left to right.
Next m line each line has two number L,R(1<=L<=R<=n),mean we want to know the answer of [L,R].

 

 

Output

For every query output a number indicate there should be how many group so that the sum of value is max.

扫描二维码关注公众号,回复: 5720001 查看本文章

 

 

Sample Input

 

1
10 6
1 3 5 7 9 10 8 6 4 2
1 10
2 9
3 8
7 9
4 7
5 6

 

 

Sample Output

 

1
1
1
3
1
1

题目大意:

        给出n个数字,m个询问(范围都在[1, 1e5]),每个数字只会出现一次,定义连续的数字都分为一组,每个询问都会包含一个区间[l, r],问区间内的分组。

解题思路:

        使用莫队算法离线查询答案,将询问分块排序,先按l/sqrt(n)排序,再按r排序。暴力循环求解区间加减1的答案。

        维护一个mask[]表示暴力过程中是否已经存在数字。

        区间扩展时:设扩展左或右1个大小的区间,扩展的数字是x。那么只需看mask[x-1]和mask[x+1]是否都存在序列中或者是否都不存在于已知序列中。都存在那么就表示x将两个group合并为一个group答案减一,都不存在就表示x是独立一个group答案加一,其它情况x加在其它group的边界不影响答案所以不用考虑。

        区间缩减时:同理。

AC代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;

const int N = int(1e5 + 5);

int g_arr[N];
int g_n, g_m;
int g_block;

typedef struct _Node
{
    int l, r;
    int idx;
    bool operator <(const struct _Node &otr) const
    {
        if (this->l / g_block == otr.l / g_block) return this->r < otr.r;
        else return this->l < otr.l; 
    }
} Node;

Node g_ask[N];
int g_ans[N];
int g_mask[N];

inline void scaleUp(const int &val, int &rst)
{
    if (g_mask[val]) return; // arr数组时unique的,可以不用考虑,但还是加上符合逻辑
    g_mask[val] = 1;
    if (g_mask[val - 1] && g_mask[val + 1]) rst--;
    else if (!g_mask[val -1] && !g_mask[val + 1]) rst++;
}

inline void scaleDown(const int &val, int &rst)
{
    if (!g_mask[val]) return; // arr数组时unique的,可以不用考虑,但还是加上符合逻辑
    g_mask[val] = 0;
    if (g_mask[val - 1] && g_mask[val + 1]) rst++;
    else if (!g_mask[val -1] && !g_mask[val + 1]) rst--;
}

void executeFun()
{
    memset(g_mask, 0, sizeof(g_mask));
    int i;
    int l = 1, r = 0, t = 0;
    for (i = 0; i < g_m; i++)
    {
        // 注意:在此题中先算l和先算r有区别,其它题视题意而定
        // 因为l有可能会减,而scaleDown方法在mask起始为0时会不执行
        // 这时r为0,所以r只会scaleUp,先将mask标记为1,再调用scaleDown(l)就不会有问题
        while (r > g_ask[i].r) scaleDown(g_arr[r--], t);
        while (r < g_ask[i].r) scaleUp(g_arr[++r], t);
        while (l < g_ask[i].l) scaleDown(g_arr[l++], t);
        while (l > g_ask[i].l) scaleUp(g_arr[--l], t);
        g_ans[g_ask[i].idx] = t;
    }
}

int main()
{
    int T, i;
    scanf("%d", &T);
    while (T--)
    {
        scanf("%d%d", &g_n, &g_m);
        g_block = (int) sqrt(g_n);
        for (i = 1 ; i <= g_n; i++)
        {
            scanf("%d", &g_arr[i]);
        }
        for (i = 0; i < g_m; i++)
        {
            scanf("%d%d", &g_ask[i].l, &g_ask[i].r);
            g_ask[i].idx = i;
        }
        sort(g_ask, g_ask + g_m);
        executeFun();
        for (i = 0; i < g_m; i++)
        {
            printf("%d\n", g_ans[i]);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_41645983/article/details/88775473