Census【离线树状数组】

版权声明:https://blog.csdn.net/qq_41730082 https://blog.csdn.net/qq_41730082/article/details/86474209

This year, there have been many problems with population calculations, since in some cities, there are many emigrants, or the population growth is very high. Every year the ACM (for Association for Counting Members) conducts a census in each region. The country is divided into N ∧ 2 regions, consisting of an N × N grid of regions. Your task is to find the least, and the greatest population in some set of regions. Since in a single year there is no significant change in the populations, the ACM modifies the population counts by some number of inhabitants. Input In the first line you will find N (0 ≤ N ≤ 500), in following the N lines you will be given N numbers, wich represent, the initial population of city C[i, j]. In the following line is the number Q (Q ≤ 40000), followed by Q lines with queries: There are two possible queries: • ‘q x1 y1 x2 y2’ which represent the coordinates of the upper left and lower right of where you must calculate the maximum and minimum change in population. • ‘c x y v’ indicating a change of the population of city C[x, y] by value v. Output For each query, ‘q x1 y1 x2 y2’ print in a single line the greatest and least amount of current population. Separated each output by a space. Notice: There is only a single test case. Sample Input 5 1 2 3 4 5 0 9 2 1 3 0 2 3 4 1 0 1 2 4 5 8 5 3 1 4 4 q 1 1 2 3 c 2 3 10 q 1 1 5 5 q 1 2 2 2 Sample Output 9 0 10 0 9 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;
}

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/86474209