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.

 

 

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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值