HDU 4638 Group 树状数组离线

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4638

题意:给定一个长度为n的数组,数组中元素为1到n,询问某个区间内有多少段连续的数字

思路:之前用莫队算法写的,很简单,今天用树状数组离线搞得,感觉不如莫队好想,但是效率高了将近一倍。把询问按照右端点从小到大排序,对于每个数,我们看成是孤立的,更新到树状数组上,即把这个位置加1,然后判断这个数的左右相邻数字是否已经更新到树状数组中,若已更新则去掉,那么求某个区间内连续数字的段数变转换为求区间和

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

typedef long long ll;
const int N = 100010;
int bit[N], res[N];
int a[N], b[N], pos[N];
bool vis[N];
int n, m;
struct node
{
    int l, r, id;
} g[N];
void add(int i, int x)
{
    while(i <= n) bit[i] += x, i += i & -i;
}
int sum(int i)
{
    ll s = 0;
    while(i > 0) s += bit[i], i -= i & -i;
    return s;
}
bool cmp(node a, node b)
{
    return a.r < b.r;
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &n, &m);
        memset(bit, 0, sizeof bit);
        memset(vis, 0, sizeof vis);
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]), pos[a[i]] = i;
        for(int i = 1; i <= m; i++) scanf("%d%d", &g[i].l, &g[i].r), g[i].id = i;
        sort(g+1, g+1+m, cmp);
        int tot = 1;
        for(int i = 1; i <= n; i++)
        {
            add(i, 1);//把每一个数都看成孤立的,故+1
            //若这个数的左右相近数字已经更新到树状数组中,要对应的-1
            if(a[i] - 1 >= 1 && pos[a[i]-1] < i) add(pos[a[i]-1], -1);
            if(a[i] + 1 <= n && pos[a[i]+1] < i) add(pos[a[i]+1], -1);
            while(tot <= m && g[tot].r == i)
                res[g[tot].id] = sum(g[tot].r) - sum(g[tot].l - 1), tot++;
        }
        for(int i = 1; i <= m; i++) printf("%d\n", res[i]);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值