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

Posted water-mi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
", ans);
    }
    return 0;
}

以上是关于Bzoj4548 小奇的糖果(链表+树状数组)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj4548小奇的糖果 STL-set+树状数组

[BZOJ4548]小奇的糖果

bzoj4548: 小奇的糖果 题解

bzoj 4548 小奇的糖果

BZOJ4550小奇的博弈 博弈论

BZOJ4547Hdu5171 小奇的集合 矩阵乘法