bzoj 4548 小奇的糖果

bzoj

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

#include<bits/stdc++.h>
#define LL long long
#define uLL unsigned long long
#define db double

using namespace std;
const int N=3e5+10;
int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
int n,kk,q,ans,sq[N];
int bx[N],mx,by[N],my;
int bt[N];
void add(int x,int y){while(x<=mx) bt[x]+=y,x+=x&(-x);}
int gsm(int x){int an=0;while(x) an+=bt[x],x-=x&(-x);return an;}
struct node
{
    int x,y;
    bool operator < (const node &bb) const {return y!=bb.y?y<bb.y:x<bb.x;}
}a[N];
vector<int> st[N];
int stk[N],tp;
bool cmp(int aa,int bb){return a[aa]<a[bb];}
set<int> sb;
set<int>::iterator ft,nt;
struct qq
{
    int l,r,y;
    bool operator < (const qq &bb) const {return y<bb.y;}
}qr[N<<1];
void wk()
{
    q=0;
    for(int i=1;i<=kk;++i)
    {
        if(st[i].empty()){ans=n;break;}
        sb.clear(),sb.insert(1),sb.insert(mx);
        sort(st[i].begin(),st[i].end(),cmp);

        vector<int>::iterator it;
        int las=-1;
        tp=0;
        for(it=st[i].begin();it!=st[i].end();++it)
        {
            int j=*it;
            if(a[j].y!=las)
            {
                las=a[j].y;
                while(tp)
                    sb.insert(a[stk[tp]].x),--tp;
            }
            nt=sb.upper_bound(a[j].x);
            ft=--nt,++nt;
            if(*ft!=a[j].x)
            {
                qr[++q]=(qq){(*ft)+1,(*nt)-1,a[j].y-1};
                stk[++tp]=j;
            }
        }
        while(tp)
            sb.insert(a[stk[tp]].x),--tp;
        ft=sb.begin(),nt=++ft,--ft;
        for(;nt!=sb.end();++ft,++nt)
            qr[++q]=(qq){(*ft)+1,(*nt)-1,my-1};
    }
    sort(qr+1,qr+q+1);
    for(int i=1;i<=n+1;++i) sq[i]=i;
    a[n+1].y=my+1;
    sort(sq+1,sq+n+2,cmp);
    memset(bt,0,sizeof(int)*(mx+1));
    for(int i=1,j=1,k=1;i<=n+1;++j)
    {
        while(k<=q&&qr[k].y<a[sq[i]].y)
        {
            ans=max(ans,gsm(qr[k].r)-gsm(qr[k].l-1));
            ++k;
        }
        while(j<=n&&a[sq[j+1]].y==a[sq[j]].y) ++j;
        while(i<=j) add(a[sq[i]].x,1),++i;
    }
}

int main()
{
    int T=rd();
    while(T--)
    {
        n=rd(),kk=rd();
        for(int i=1;i<=kk;++i) st[i].clear();
        mx=my=0;
        bx[++mx]=-2147483648,bx[++mx]=2147483647;
        by[++my]=-2147483648,by[++my]=2147483647;
        for(int i=1;i<=n;++i)
        {
            a[i].x=rd()*2,a[i].y=rd()*2;
            bx[++mx]=a[i].x,bx[++mx]=a[i].x-1,bx[++mx]=a[i].x+1;
            by[++my]=a[i].y,by[++my]=a[i].y-1,by[++my]=a[i].y+1;
            st[rd()].push_back(i);
        }
        sort(bx+1,bx+mx+1),mx=unique(bx+1,bx+mx+1)-bx-1;
        for(int i=1;i<=mx;++i) a[i].x=lower_bound(bx+1,bx+mx+1,a[i].x)-bx;
        sort(by+1,by+my+1),my=unique(by+1,by+my+1)-by-1;
        for(int i=1;i<=my;++i) a[i].y=lower_bound(by+1,by+my+1,a[i].y)-by;
        ans=0;
        wk();
        for(int i=1;i<=n;++i) a[i].y=my-a[i].y+1;
        wk();
        printf("%d\n",ans);
    }
    return 0;
}
彩蛋

本题题意应该是~~有 N 个彩色糖果在平面上。小奇想在平面上取一条**直线**,并拾起它上方或下方的所有糖果。求出最多能够拾起多少糖果,使得获得的糖果并不包含**相同**的颜色。~~

其实是我看错了qwq

原文地址:https://www.cnblogs.com/smyjr/p/11559619.html

时间: 2024-11-10 19:07:46

bzoj 4548 小奇的糖果的相关文章

[乱搞 树状数组] 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

【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 组测试数据,对于每组测试数据,第

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

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

[BZOJ4548]小奇的糖果

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

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

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

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

BZOJ 1022 小约翰的游戏 (Anti-Nim游戏)

题解:注意题目中规定取到最后一粒石子的人算输,所以是Anti-Nim游戏,胜负判断为: 先手必胜: 1.所有堆的石子数都为1且游戏的SG值为0: 2.有些堆的石子数大于1且游戏的SG值不为0. #include <cstdio> int main(){ int t,n,s,x,tmp; scanf("%d",&t); while(t--){ scanf("%d",&n); for(s=tmp=0;n--;)scanf("%d&q

【NOIP模拟赛】小奇挖矿 2

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