树状数组-赏花(nkoj2387)

树状数组-赏花(nkoj2387)

题意分析

询问[l,r]元素种类数

树状数组(带标记)

带标记的树状数组

  • 提问可以离线处理最后输出(如果强制在线那又要怎么做?)
  • 把颜色转化为0/1标记(记录下next和first/last,然后每个fisrt对应的值置1,l移动的时候就把l对应的地方置0,next[l]对应的值置1)
  • 然后求前缀和(树状数组)即是种类数

代码

//
// Created by rv on 2018/4/23.
//

#include <stdio.h>
#include <string.h>

const int BUFFER_SIZE = 10 << 20;
char buffer[BUFFER_SIZE];
char* ptr = buffer;

const int N = 100000 + 5;
const int M = 200000 + 5;
int c[N], next[N], first[N], qlast[N], qnext[M], R[M], ans[M];

struct BIT {
    int n;
    int* b;
    // TODO: private的拷贝构造
    BIT(int _n) {
        b = new int[_n];
        n = _n;
        memset(b, 0, n * sizeof(int));
    }
    void add(int pos, int delta) {
        for (int i = pos; i <= n; i += i & -i) {
            b[i] += delta;
        }
    }
    int sum(int pos) {
        int res = 0;
        for (int i = pos; i >= 1; i -= i & -i) {
            res += b[i];
        }
        return res;
    }
};

inline void read_int(int& x) {
    x = 0;
    while (*ptr < '0' || *ptr > '9') {
        ptr++;
    }
    while (*ptr >= '0' && *ptr <= '9') {
        x = x * 10 + (*ptr - '0');
        ptr++;
    }
}

int main() {
    fread(buffer, 1, BUFFER_SIZE, stdin);
    int n, m, l, r, C;
    read_int(n);
    BIT bit(n + 1);
    C = -1;
    for (int i = 1; i <= n; i++) {
        read_int(c[i]);
        C = c[i] > C ? c[i] : C;
    }
    read_int(m);
    for (int i = 1; i <= m; i++) {
        read_int(l);
        read_int(r);
        qnext[i] = qlast[l];
        qlast[l] = i;
        R[i] = r;
    }
    for (int i = n; i >= 1; i--) {
        next[i] = first[c[i]];
        first[c[i]] = i;
    }
    for (int i = 1; i <= C; i++) {
        if (first[i] > 0) {
            bit.add(first[i], 1);
        }
    }
//    for (int i = 1; i <= m; i++) {
//        printf("%d\n", R[i]);
//    }
    for (l = 1; l <= n; l++) {
        for (int i = qlast[l]; i >= 1; i = qnext[i]) {
            ans[i] = bit.sum(R[i]);
        }
        bit.add(l, -1);
        if (next[l] > 0) {
            bit.add(next[l], 1);
        }
    }
    for (int i = 1; i <= m; i++) {
        printf("%d\n", ans[i]);
    }
    return 0;
}

PS

坏习惯:

每次都忘记赋初值,每次都没有处理边界情况,写的每一个字符都没有考虑,范围没有搞清楚就写下去了,小问题很多(以后要做到写完每一句话就把这句话静态调试一遍)

运行时间0ms原理:

使用stdio.h和fread读入即可大幅度提升速度,然后就几乎测不出运行时间(Windows的最小运行时间片是15ms)

fread读入优化:
fread(readBuffer, 1, MAX_BUFFER_SIZE, stdin);

猜你喜欢

转载自blog.csdn.net/xenoncat/article/details/80225309