Bzoj4548 小奇的糖果(链表+树状数组)

题面

Bzoj

题解

很显然,我们只需要考虑单独取线段上方的情况,对于下方的把坐标取反再做一遍即可(因为我们只关心最终的答案)

建立树状数组维护一个横坐标区间内有多少个点,维护双向链表实现查询一个点左(右)横坐标最大(小)的与它相同的点。

首先枚举没有取到的颜色,找出所有不包含这种颜色的区间,更新答案。

接着考虑两个相同颜色的点的贡献,按照纵坐标从大到小枚举所有的点,分别在树状数组和双向链表中删除当前点,并利用这个点左右两边和它颜色相同的点之间的区间内点的个数更新答案。

#include <cstdio>
#include <cstring>
#include <algorithm>
using std::min; using std::max;
using std::sort; using std::swap;
using std::unique; using std::lower_bound;
typedef long long ll;

template<typename T>
void read(T &x) {
    int flag = 1; x = 0; char ch = getchar();
    while(ch < '0' || ch > '9') { if(ch == '-') flag = -flag; ch = getchar(); }
    while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= flag;
}

const int N = 1e5 + 10;
int T, n, K, x[N], ans;
struct data { int x, y, z, id; } p[N];
int disc[N], t[N];//树状数组
int last[N], l[N], r[N];//双向链表

void add (int x, int y) { while(x <= n + 1) t[x] += y, x += (x & -x); }
int query (int x) { int y = 0; while(x) y += t[x], x -= (x & -x); return y; }
inline bool cmpx(const data &a, const data &b) { return a.x < b.x; }
inline bool cmpy(const data &a, const data &b) { return a.y < b.y; }
void update(int l, int r) {
    if(l > r) return ;
    int tmp = query(r) - query(l - 1);
    ans = max(tmp, ans);
}

void doit () {
    x[0] = 0, x[n + 1] = n + 1;
    memset(last, 0, sizeof last), memset(t, 0, sizeof t);
    sort(&p[1], &p[n + 1], cmpx);
    for(int i = 1; i <= n; ++i) add(p[i].x, 1);
    for(int i = 1; i <= n; ++i) {
        int t = p[i].id, L= last[p[i].z];
        l[t] = L, r[t] = n + 1;
        if(L) r[L] = t;
        update(x[L] + 1, x[t] - 1);
        last[p[i].z] = t;
    }
    for(int i = 1; i <= K; ++i)
        update(x[last[i]] + 1, n + 1);
    sort(&p[1], &p[n + 1], cmpy);
    for(int i = 1, j = 1; i <= n; ++i) {
        int t = p[i].id;
        while(j <= n && p[j].y == p[i].y) add(p[j].x, - 1), ++j;
        l[r[t]] = l[t], r[l[t]] = r[t];
        update(x[l[t]] + 1, x[r[t]] - 1);
    }
}

int main () {
    read(T);
    while(T--) {
        ans = 0, read(n), read(K); int m = n;
        for(int i = 1; i <= n; ++i)
            read(p[i].x), read(p[i].y), read(p[i].z), p[i].id = i;
        for(int i = 1; i <= n; ++i)
            disc[i] = p[i].x;
        sort(&disc[1], &disc[m + 1]), m = unique(&disc[1], &disc[m + 1]) - disc - 1;
        for(int i = 1; i <= n; ++i) {
            p[i].x = lower_bound(&disc[1], &disc[m + 1], p[i].x) - disc;
            x[i] = p[i].x;
        }
        doit(); for(int i = 1; i <= n; ++i) p[i].y = -p[i].y; doit();
        printf("%d\n", ans);
    }
    return 0;
}