【BZOJ4548】小奇的糖果

来源:互联网 发布:linux sqlplus 登录 编辑:程序博客网 时间:2024/04/27 18:56

Description

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

Solution

看到平面坐标系上维护一些点的数量,我们可以用排序降一维。

具体来说,我们将x坐标离散化,然后做一条平行于x轴的扫描线,动态维护当前扫描到的点的数量。

对于这题,我们先考虑在扫描线上方的点(下方的同理),假如这条线段在最下方,那么我们可以枚举一种颜色不选,然后统计颜色相同横坐标最靠近两个点之间的点的数量,然后对答案取max。维护这个,可以用双向链表,即维护一个点左(右)边横坐标最大(小)的与它颜色相同的点。

接下来按y坐标排序,扫描线向上移,现在要删掉扫描线上的点,然后我们考虑删掉之后使点数增加的情况。那么对于一个被删掉的点,我们找到它在双向链表前后两个点,那么此时两个点之间的点且在扫描线上方的就可以对答案取max。(这里注意先删去点,再统计)

于是把y坐标取反再排序,重新做一次即可。

维护点的数量可以用树状数组或线段树实现。

Code

#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define fo(i,j,k) for(int i=j;i<=k;i++)#define fd(i,j,k) for(int i=j;i>=k;i--)#define N 100010using namespace std;struct node{    int x,y,c;    int nx,wz;}b[N*2];bool cmpc(node x,node y){    if(x.c==y.c) return x.x<y.x;    else return x.c<y.c;}bool cmpy(node x,node y){    return x.y<y.y;}bool cmpx(node x,node y){    return x.nx<y.nx;}int mx=0,n,m;int nx[N*2],ls[N*2];int sn[N*2],sl[N*2];bool bz[N];void link(int x,int y){    nx[x]=y,ls[y]=x;}void cut(int x){    nx[ls[x]]=nx[x],ls[nx[x]]=ls[x];}int ans=0;int top[N],tr[N];int lowbit(int x){    return x & -x;}void add(int x,int t){    while(x<=mx) tr[x]+=t,x+=lowbit(x);}int sum(int x){    int tmp=0;    while(x) tmp+=tr[x],x-=lowbit(x);    return tmp;}int tot;int wz[N];void calc(){    sort(b+1,b+n+1,cmpy);    fo(i,1,n) wz[b[i].wz]=i;    int p=0;    fo(i,1,n)    {        while(b[p+1].y==b[i].y && p<n) add(b[++p].x,-1);        fo(j,i,p)        {            int o=b[j].wz,tmp=0;            int l=ls[o],r=nx[o];            if(l<=n) l=wz[l];            if(r<=n) r=wz[r];             if(b[l].x<b[r].x-1) tmp=sum(b[r].x-1)-sum(b[l].x);            if(tmp>ans) ans=tmp;            cut(o);        }        i=p;    }}int main(){    int T;    scanf("%d",&T);    while(T--)    {        scanf("%d %d",&n,&m);        fo(i,1,n) scanf("%d %d %d",&b[i].nx,&b[i].y,&b[i].c),bz[b[i].c]=true;        int cnt=0;        fo(i,1,m) if(bz[i]) cnt++;        if(cnt<m)        {            printf("%d\n",n);            continue;        }        sort(b+1,b+n+1,cmpx);        mx=0;        b[1].x=++mx;        fo(i,2,n) if(b[i].nx!=b[i-1].nx) b[i].x=++mx;        else b[i].x=mx;        tot=n;        sort(b+1,b+n+1,cmpc);//Datum        ans=0;        fo(i,1,n)        {            add(b[i].x,1);            b[i].wz=i;            if(b[i].c!=b[i-1].c) top[b[i].c]=++tot,link(tot,i);            else link(i-1,i);            if(b[i].c!=b[i+1].c) b[++tot].x=mx+1,link(i,tot);        }        fo(i,1,m)        {            int j=top[i];            while(nx[j])            {                if(b[j].x<b[nx[j]].x-1)                {                    int tmp=sum(b[nx[j]].x-1)-sum(b[j].x);                    if(tmp>ans) ans=tmp;                }                j=nx[j];            }        }        memcpy(sn,nx,sizeof(nx));        memcpy(sl,ls,sizeof(ls));        calc();        fo(i,1,n) b[i].y=-b[i].y,add(b[i].x,1);        memcpy(nx,sn,sizeof(sn));        memcpy(ls,sl,sizeof(sl));        calc();        printf("%d\n",ans);        memset(nx,0,sizeof(nx));        memset(ls,0,sizeof(ls));        memset(bz,0,sizeof(bz));    }}
原创粉丝点击