HDU 4638Group 树状数组离线

来源:互联网 发布:win10怎么安装sql 编辑:程序博客网 时间:2024/06/05 11:07

题目: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
原创粉丝点击