BZOJ 4548 小奇的糖果

Problem

BZOJ

Solution

只想到一个 O ( n 2 ) 的做法,大概是这样。显然固定左端点,右端点扩展后矩形高度单调不升,那么就可以维护竖直和水平的两种链表,枚举左端点,然后不断扩展右端点,颜色数为k时就高度减小。

O ( n log n ) 的做法比较巧妙,把矩形分为三类,一类是高度就是n的,另外两类就是上接和下接的。
考虑用树状数组按x轴维护点的个数。把x坐标离散化之后,用链表把x坐标相邻的同样颜色的点接起来,然后枚举即可。考虑上接的矩形,把点重新按y轴排序,从最小的开始枚举点,把y坐标小于等于它的全删除,那么矩形的左右就可以扩展到链表相接的左右端点。对于下下接的呢?直接把y坐标取负,再做同样的操作即可。

Code

#include <algorithm>
#include <cstring>
#include <cstdio>
#define rg register
#define lowbit(x) ((x)&(-(x)))
using namespace std;
typedef long long ll;
const int maxn=100010;
template <typename Tp> inline void getmin(Tp &x,Tp y){if(y<x) x=y;}
template <typename Tp> inline void getmax(Tp &x,Tp y){if(y>x) x=y;}
template <typename Tp> inline void read(Tp &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    if(f) x=-x;
}
struct data{
    int x,y,c,id;
    bool operator < (const data &t)const{return x<t.x;}
}p[maxn];
int z,n,k,tot,ans,a[maxn],b[maxn],w[maxn],l[maxn],r[maxn],pre[maxn];
inline int cmp(data a,data b){return a.y<b.y;}
void add(int p,int v){for(;p<=n;p+=lowbit(p)) a[p]+=v;}
int query(int p,int res=0){for(;p;p-=lowbit(p)) res+=a[p];return res;}
void input()
{
    read(n);read(k);ans=0;
    for(rg int i=1;i<=n;i++)
    {
        read(p[i].x);read(p[i].y);read(p[i].c);p[i].id=i;
        b[i]=p[i].x;
    }
    sort(b+1,b+n+1);
    tot=unique(b+1,b+n+1)-b-1;
    for(rg int i=1;i<=n;i++)
    {
        p[i].x=lower_bound(b+1,b+tot+1,p[i].x)-b;
        w[i]=p[i].x;
    }
}
inline void update(int l,int r){if(l<=r) getmax(ans,query(r)-query(l-1));}
void solve()
{
    int x,y;
    memset(a,0,sizeof(a));
    memset(pre,0,sizeof(pre));
    sort(p+1,p+n+1);w[0]=0;w[n+1]=n+1;
    for(rg int i=1;i<=n;i++) add(p[i].x,1);
    for(rg int i=1;i<=n;i++)
    {
        x=p[i].id;y=pre[p[i].c];
        l[x]=y;r[x]=n+1;
        if(y) r[y]=x;
        update(w[y]+1,w[x]-1);
        pre[p[i].c]=x;
    }
    for(rg int i=1;i<=k;i++) update(w[pre[i]]+1,n+1);
    sort(p+1,p+n+1,cmp);
    for(rg int i=1,j=1;i<=n;i++)
    {
        x=p[i].id;
        while(j<=n&&p[j].y==p[i].y) add(p[j++].x,-1);
        l[r[x]]=l[x];r[l[x]]=r[x];
        update(w[l[x]]+1,w[r[x]]-1);
    }
}
int main()
{
    freopen("in.txt","r",stdin);
    read(z);
    while(z--)
    {
        input();
        solve();
        for(rg int i=1;i<=n;i++) p[i].y=-p[i].y;
        solve();
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/as_a_kid/article/details/81193612
今日推荐