[BZOJ4548]小奇的糖果

[BZOJ4548]小奇的糖果

试题描述

有 \(N\) 个彩色糖果在平面上。小奇想在平面上取一条水平的线段,并拾起它上方或下方的所有糖果。求出最多能够拾起多少糖果,使得获得的糖果并不包含所有的颜色。

输入

包含多组测试数据,第一行输入一个正整数 \(T\) 表示测试数据组数。

接下来 \(T\) 组测试数据,对于每组测试数据,第一行输入两个正整数 \(N\)、\(K\),分别表示点数和颜色数。

接下来 \(N\) 行,每行描述一个点,前两个数 \(x, y (|x|, |y| \le 2^{30} - 1)\) 描述点的位置,最后一个数 \(z (1 \le z ≤ k)\) 描述点的颜色。

输出

对于每组数据在一行内输出一个非负整数 \(ans\),表示答案

输入示例

1
10 3
1 2 3
2 1 1
2 4 2
3 5 3
4 4 2
5 1 2
6 3 1
6 7 1
7 2 3
9 4 2

输出示例

5

数据规模及约定

对于 \(100\%\) 的数据,\(N \le 100000,K \le 100000,T \le 3\)

题解

此题和那道题是双倍经验关系。

然而我那道题的做法在这里直接 T 飞了,所以再讲一个不那么慢的做法。(虽然也是基本垫底)

如果给出的点没有提到所有颜色,就直接输出 \(n\)。

枚举不能包含的那个颜色 \(c\),令所有颜色为 \(c\) 的点的集和为 \(S_c\)。将 \(S_c\) 中的点按 \(x\) 坐标排序,然后我们从左到右依次考虑每个点,并以 \(y\) 坐标为关键字维护单调栈,当删除单调栈中的元素时统计一下极大子矩形的答案。询问矩形内部点数可以用主席树一个 \(\log n\) 做。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <vector>
using namespace std;
#define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
#define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)

int read() {
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = getchar(); }
    return x * f;
}

#define maxn 100010
#define maxnode 2000010
#define pii pair <int, int>
#define x first
#define y second
#define mp(x, y) make_pair(x, y)

int n, K, nX[maxn], nY[maxn];
pii ps[maxn];
vector <pii > col[maxn];
bool cmpy(pii a, pii b) { return a.y < b.y; }

int ToT, rt[maxn], sumv[maxnode], lc[maxnode], rc[maxnode];
void update(int& y, int x, int l, int r, int p) {
    sumv[y = ++ToT] = sumv[x] + 1;
    if(l == r) return ;
    int mid = l + r >> 1; lc[y] = lc[x]; rc[y] = rc[x];
    if(p <= mid) update(lc[y], lc[x], l, mid, p);
    else update(rc[y], rc[x], mid + 1, r, p);
    return ;
}
int query(int o, int l, int r, int ql, int qr) {
    if(!o) return 0;
    if(ql <= l && r <= qr) return sumv[o];
    int mid = l + r >> 1, ans = 0;
    if(ql <= mid) ans += query(lc[o], l, mid, ql, qr);
    if(qr > mid) ans += query(rc[o], mid + 1, r, ql, qr);
    return ans;
}
int Query(int xl, int xr, int yl, int yr) {
    if(xl > xr || yl > yr) return 0;
    return query(rt[yr], 1, n, xl, xr) - query(rt[yl-1], 1, n, xl, xr);
}

int S[maxn], top;
void work() {
    ToT = 0;
    memset(rt, 0, sizeof(rt));
    memset(lc, 0, sizeof(lc));
    memset(rc, 0, sizeof(rc));

    n = read(); K = read();
    rep(c, 1, K) col[c].clear();
    rep(i, 1, n) {
        int x = read(), y = read(), c = read();
        nX[i] = x; nY[i] = y;
        ps[i] = mp(x, y);
        col[c].push_back(ps[i]);
    }
    sort(nX + 1, nX + n + 1);
    sort(nY + 1, nY + n + 1);
    rep(i, 1, n)
        ps[i].x = lower_bound(nX + 1, nX + n + 1, ps[i].x) - nX,
        ps[i].y = lower_bound(nY + 1, nY + n + 1, ps[i].y) - nY;
    rep(c, 1, K) {
        if(!col[c].size()) return (void)printf("%d\n", n);
        rep(i, 0, (int)col[c].size() - 1) {
            pii& p = col[c][i];
            p.x = lower_bound(nX + 1, nX + n + 1, p.x) - nX;
            p.y = lower_bound(nY + 1, nY + n + 1, p.y) - nY;
        }
    }
    sort(ps + 1, ps + n + 1, cmpy);
    int j = 1;
    rep(i, 1, n) {
        rt[i] = rt[i-1];
        while(j <= n && ps[j].y == i) update(rt[i], rt[i], 1, n, ps[j++].x);
    }
    int ans = 0;
    rep(c, 1, K) {
        sort(col[c].begin(), col[c].end());
        // optimus
        rep(i, 0, (int)col[c].size() - 1) ans = max(ans, Query(i ? col[c][i-1].x + 1 : 1, col[c][i].x - 1, 1, n));
        ans = max(ans, Query(col[c][col[c].size()-1].x + 1, n, 1, n));
        // down
        rep(i, 0, (int)col[c].size() - 1) {
            pii now = col[c][i];
            while(top && col[c][S[top]].y > now.y) {
                ans = max(ans, Query(top > 1 ? col[c][S[top-1]].x + 1 : 1, now.x - 1, 1, col[c][S[top]].y - 1));
                top--;
            }
            S[++top] = i;
        }
        while(top) {
            ans = max(ans, Query(top > 1 ? col[c][S[top-1]].x + 1 : 1, n, 1, col[c][S[top]].y - 1));
            top--;
        }
        // up
        rep(i, 0, (int)col[c].size() - 1) {
            pii now = col[c][i];
            while(top && col[c][S[top]].y < now.y) {
                ans = max(ans, Query(top > 1 ? col[c][S[top-1]].x + 1 : 1, now.x - 1, col[c][S[top]].y + 1, n));
                top--;
            }
            S[++top] = i;
        }
        while(top) {
            ans = max(ans, Query(top > 1 ? col[c][S[top-1]].x + 1 : 1, n, col[c][S[top]].y + 1, n));
            top--;
        }
    }
    printf("%d\n", ans);
    return ;
}

int main() {
    int T = read();

    while(T--) work();

    return 0;
}

原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/8479472.html

时间: 2024-10-11 10:22:16

[BZOJ4548]小奇的糖果的相关文章

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

题面 Bzoj 题解 很显然,我们只需要考虑单独取线段上方的情况,对于下方的把坐标取反再做一遍即可(因为我们只关心最终的答案) 建立树状数组维护一个横坐标区间内有多少个点,维护双向链表实现查询一个点左(右)横坐标最大(小)的与它相同的点. 首先枚举没有取到的颜色,找出所有不包含这种颜色的区间,更新答案. 接着考虑两个相同颜色的点的贡献,按照纵坐标从大到小枚举所有的点,分别在树状数组和双向链表中删除当前点,并利用这个点左右两边和它颜色相同的点之间的区间内点的个数更新答案. #include <cs

【BZOJ4548】小奇的糖果 set(链表)+树状数组

[BZOJ4548]小奇的糖果 Description 有 N 个彩色糖果在平面上.小奇想在平面上取一条水平的线段,并拾起它上方或下方的所有糖果.求出最多能够拾起多少糖果,使得获得的糖果并不包含所有的颜色. Input 包含多组测试数据,第一行输入一个正整数 T 表示测试数据组数. 接下来 T 组测试数据,对于每组测试数据,第一行输入两个正整数 N.K,分别表示点数和颜色数. 接下来 N 行,每行描述一个点,前两个数 x, y (|x|, |y| ≤ 2^30 - 1) 描述点的位置,最后一个数

【BZOJ-4548&amp;3658】小奇的糖果&amp;Jabberwocky 双向链表 + 树状数组

4548: 小奇的糖果 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 103  Solved: 47[Submit][Status][Discuss] Description 有 N 个彩色糖果在平面上.小奇想在平面上取一条水平的线段,并拾起它上方或下方的所有糖果.求出最多能够拾 起多少糖果,使得获得的糖果并不包含所有的颜色. Input 包含多组测试数据,第一行输入一个正整数 T 表示测试数据组数. 接下来 T 组测试数据,对于每组测试数据,第

bzoj 4548 小奇的糖果

bzoj 他要求不包含所有颜色,那我们可以强制某种颜色不被包含.枚举每一种颜色,然后按纵坐标从小到大排序.枚举到一个点,我们要考虑在它下面一点的线段能取的最大的区域,那么左右端点分别是之前加入了的纵坐标更小离他最近的点,这个可以用以横坐标为关键字的set找.另外要把上面没有这种点的线段与下面点构成的区域也加进来.这里只考虑了往下取,可以所有点纵坐标颠倒后再来一次,就求出所有可选的矩形区域,然后扫描线二维数点 #include<bits/stdc++.h> #define LL long lon

[乱搞 树状数组] BZOJ 4548 小奇的糖果 &amp;&amp; BZOJ 3658 Jabberwocky

跟悬线法有点像 #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #define cl(x) memset(x,0,sizeof(x)) using namespace std; inline char nc() { static char buf[100000],*p1=buf,*p2=buf; if (p1==p2) { p2=(p1=buf)+fread(b

AC日记——小A的糖果 洛谷七月月赛

小A的糖果 思路: for循环贪心: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #define ll long long ll ai[maxn],n,m,ans; inline void in(ll &now) { char Cget=getchar();now=0; while(Cget>'9'||Cget<'0')Cget=getchar(); while(Cget>

luogu P3817 小A的糖果

P3817 小A的糖果 题目描述 小A有N个糖果盒,第i个盒中有a[i]颗糖果. 小A每次可以从其中一盒糖果中吃掉一颗,他想知道,要让任意两个相邻的盒子中加起来都只有x颗或以下的糖果,至少得吃掉几颗糖. 输入输出格式 输入格式: 第一行输入N和x. 第二行N个整数,为a[i]. 输出格式: 至少要吃掉的糖果数量. 输入输出样例 输入样例#1: 3 3 2 2 2 输出样例#1: 1 输入样例#2: 6 1 1 6 1 2 0 4 输出样例#2: 11 输入样例#3: 5 9 3 1 4 1 5

【NOIP模拟赛】小奇挖矿 2

[题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿石交易市场,以便为飞船升级无限非概率引擎. [问题描述] 现在有m+1个星球,从左到右标号为0到m,小奇最初在0号星球. 有n处矿体,第i处矿体有ai单位原矿,在第bi个星球上. 由于飞船使用的是老式的跳跃引擎,每次它只能从第x号星球移动到第x+4号星球或x+7号星球.每到一个星球,小奇会采走该星球上所有的原矿,求小奇能采到的最大原矿数量. 注意,小奇不必最终到达m号星球. [输入格式] 第一行2个整数n,m

4711: 小奇挖矿

4711: 小奇挖矿 Description [题目背景] 小奇在喵星系使用了无限非概率驱动的采矿机,以至于在所有星球上都采出了一些矿石,现在它准备建一些矿石仓 库并把矿石运到各个仓库里. [问题描述] 喵星系有n个星球,标号为1到n,星球以及星球间的航线形成一棵树.所有星球间的双向航线的长度都为1.小奇要 在若干个星球建矿石仓库,设立每个仓库的费用为K.对于未设立矿石仓库的星球,设其到一个仓库的距离为i,则 将矿石运回的费用为Di.请你帮它决策最小化费用. Input 第一行2个整数n,K.