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

posted @ 2019-09-20 20:13  ✡smy✡  阅读(100)  评论(0编辑  收藏  举报