Group【HDU-4638】【离线树状数组】

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
5 2
3 1 2 5 4
1 5
2 4

Sample Output

1
2

  题面…… 反正就是这道题就对了


  题目的要求是先给出N个数,然后问的是区间内的连续数的个数(一个都不连续,就是和自己连续,也算做一组)。

  例如,我们有5个数,是{3,1,2,5,4};查询[2,4]中的连续数的个数,就是{1, 2}、{5}一共有两个,问题就是,我们该怎么去转换这个思想?

  最早的时候,我想到了是以前求区间互质数的个数,当时按照一定的顺序排序,然后先预处理质因子的每个下一位的出现的位置,做更新,但是这道题有点不实用,因为加入这个数是"4",遇上"3"、"5"就得去进行处理,但是"3"、"5"的位置之后,可能会使得"2"、"6"等等也产生了连续关系……这就不好处理了。

  然后,想个办法,如果他的左右出现在查询区间之内的话,是不是就可以递推转移了?试试看查询的左区间升序,如果递推下去的数它的左右元素值是出现过的就给予对应位置上附上+1,然后就这样不断的判断连续…… 那么,右端点的不稳定性就不好处理了,不过也可以就这样递推的,这样子的递推,就得满足每次都要到查询的端点的右区间更新,但是之前的连续关系会断掉,就不好处理了…… 

  所以,我换了种方法,把左区间降序,这样子,出现过的节点就可以附上“+1”表示它们之间的关系是存在的,若是左右区间都存在,就都+1,然后查询的每个区间,就直接用区间长度去减去关系,就可以了。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define ls rt<<1
#define rs rt<<1|1
#define Lson ls, l, mid
#define Rson rs, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 1e5 + 7;
int N, M, a[maxN], val_pos[maxN];   //val_pos[]记录的是对应的值的位置,便于处理前后缀
struct ques
{
    int l, r, id;
    ques(int a=0, int b=0, int c=0):l(a), r(b), id(c) {}
}q[maxN];
int ans[maxN];  //输出
bool cmp(ques e1, ques e2) { return e1.l > e2.l; } //按照查询的左区间降序……美滋滋
int trie[maxN];
inline void update(int i, int val)
{
    if(i == 0) return;
    while(i < maxN)
    {
        trie[i] += val;
        i += lowbit(i);
    }
}
inline int query(int i)
{
    int ans = 0;
    while(i)
    {
        ans += trie[i];
        i -= lowbit(i);
    }
    return ans;
}
int main()
{
    int T;  scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d", &N, &M);
        memset(trie, 0, sizeof(trie));
        for(int i=1; i<=N; i++)
        {
            scanf("%d", &a[i]);
            val_pos[a[i]] = i;
        }
        for(int i=1; i<=M; i++)
        {
            scanf("%d%d", &q[i].l, &q[i].r);
            q[i].id = i;
        }
        sort(q+1, q+M+1, cmp);  //按照v升序,做到可以排除连续
        int j = N;
        for(int i=1; i<=M; i++)
        {
            while(j >= q[i].l)
            {
                if(a[j] < N)
                {
                    if(val_pos[a[j] + 1] >= j)
                    {
                        update(val_pos[a[j] + 1], 1);
                    }
                }
                if(a[j] > 1)
                {
                    if(val_pos[a[j] - 1] >= j)
                    {
                        update(val_pos[a[j] - 1], 1);
                    }
                }
                j--;
            }
            ans[q[i].id] = (q[i].r - q[i].l + 1) - ( query(q[i].r) - query(q[i].l - 1) );
        }
        for(int i=1; i<=M; i++) printf("%d\n", ans[i]);
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值