[bzoj4548]【GDOI2018模拟7.14】小奇的糖果

12 篇文章 0 订阅
2 篇文章 0 订阅

Description

给出平面上n个点,每个点有颜色,求一条水平线段最多能包含多少个不包含所有颜色的点
n<=1e5

Solution

之所以写bzoj前缀是因为我是在bzoj上先过了这道题然后在OJ上卡常卡了一个下午
做法还是太naive
枚举一个不出现的颜色,就变成了许多限制
把这些限制按y坐标排序,在每个限制之前处理一下答案
那么我们就要处理出某个点下面和它在x坐标上相邻的两个点
这个东西我写了线段树,求一个矩形内的点数我写了主席树
其实这道题是卡常纪念_ (:з」∠) _
代码又臭又长不喜勿喷

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define rep(i,a) for(int i=last[a];i;i=ne[i])
#define min(a,b) (a<b)?a:b
#define max(a,b) (a>b)?a:b
using namespace std;
const int N=1e5+5;
int ty,n,k,ans,tot,cnt1,cnt2,num,sum,p,q,ss,now;
int last[N],ne[N],t[N];
int tr[N*50],le[N*50],ri[N*50],root[N];
bool bz[N];
inline int read() {
    char ch;int fl=1;;
    for(ch=getchar();ch<'0'||ch>'9';ch=getchar()) if (ch=='-') fl=-1;
    int x=ch-'0';
    for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    return x*fl;
}
struct note{int v,id;}b[N];
inline bool cmp(note x,note y) {return x.v<y.v;}
struct point{int x,y,z;}a[N];
inline bool cmp1(point x,point y) {return x.z<y.z||x.z==y.z&&x.x<y.x;}
struct treee{int max,min;}tree[N*5];
inline void link(int x,int y) {
    t[++num]=y;ne[num]=last[x];last[x]=num;
}
inline void add(int &v,int x,int l,int r,int y) {
    if (v<now) {
        v=++tot;
        tr[v]=tr[x];
        le[v]=le[x];
        ri[v]=ri[x];
    }
    tr[v]++;
    int m=(l+r)/2;
    if (l==r) return;
    if (y<=m) add(le[v],le[x],l,m,y);
    else add(ri[v],ri[x],m+1,r,y);
}
inline void query(int v,int z,int l,int r,int x,int y) {
    if (!v) return;
    if ((l==x&&r==y)||(sum+tr[v]-tr[z]<=ss)) {
        sum+=tr[v]-tr[z];
        return;
    }
    int m=(l+r)/2;
    if (y<=m) query(le[v],le[z],l,m,x,y);
    else if (x>m) query(ri[v],ri[z],m+1,r,x,y);
    else {
        int pp=ss;ss=0;
        query(le[v],le[z],l,m,x,m);
        ss=pp;
        query(ri[v],ri[z],m+1,r,m+1,y);
    }
}
inline void get_sum(int rt,int x,int l,int r) {
    if (l>r) return;
    if (rt<x) return;
    sum=0;ss=ans;
    query(root[rt],root[x-1],1,cnt2,l,r);
    ans=max(ans,sum);
}
inline void prepare() {
    fo(i,1,n) root[i]=0;
    fo(i,1,tot) tr[i]=le[i]=ri[i]=0;
    tot=0;
    fo(i,1,cnt1) {
        now=tot+1;
        rep(j,i) 
            add(root[i],root[i-1],1,cnt2,a[t[j]].y);
    }
}
inline void build(int v,int l,int r) {
    tree[v].max=0;tree[v].min=cnt2+1;
    if (l==r) return;
    int m=(l+r)/2;
    build(v*2,l,m);build(v*2+1,m+1,r);
}
inline void modify(int v,int l,int r,int x) {
    if (l==r) {
        tree[v].max=max(tree[v].max,x);
        tree[v].min=min(tree[v].min,x);
        return;
    }
    int m=(l+r)/2;
    if (x<=m) modify(v*2,l,m,x);
    else modify(v*2+1,m+1,r,x);
    tree[v].max=max(tree[v*2].max,tree[v*2+1].max);
    tree[v].min=min(tree[v*2].min,tree[v*2+1].min);
}
inline void revoke(int v,int l,int r,int x) {
    if (l==r) {
        tree[v].max=0;
        tree[v].min=cnt2+1;
        return;
    }
    int m=(l+r)/2;
    if (x<=m) revoke(v*2,l,m,x);
    else revoke(v*2+1,m+1,r,x);
    tree[v].max=max(tree[v*2].max,tree[v*2+1].max);
    tree[v].min=min(tree[v*2].min,tree[v*2+1].min);
}
inline void get_max(int v,int l,int r,int x,int y) {
    if (x>y) return;
    if (tree[v].max==0) return;
    if (l==x&&r==y) {p=max(p,tree[v].max);return;}
    int m=(l+r)/2;
    if (y<=m) get_max(v*2,l,m,x,y);
    else if (x>m) get_max(v*2+1,m+1,r,x,y);
    else {
        get_max(v*2+1,m+1,r,m+1,y);
        if (p==0) get_max(v*2,l,m,x,m);
    }
}
inline void get_min(int v,int l,int r,int x,int y) {
    if (x>y) return;
    if (tree[v].min==cnt2+1) return;
    if (l==x&&r==y) {q=min(q,tree[v].min);return;}
    int m=(l+r)/2;
    if (y<=m) get_min(v*2,l,m,x,y);
    else if (x>m) get_min(v*2+1,m+1,r,x,y);
    else {
        get_min(v*2,l,m,x,m);
        if (q==cnt2+1) get_min(v*2+1,m+1,r,m+1,y);
    }
}
inline void solve(bool flag) {
    build(1,1,cnt2);
    for(int l=1,r=0;l<=n;l=r+1) {
        while (a[r+1].z==a[l].z) r++;
        for(int left=l,right=left-1;left<=r;left=right+1) {
            while (a[right+1].x==a[left].x) right++;
            fo(i,left,right) {
                p=0;get_max(1,1,cnt2,1,a[i].y);
                q=cnt2+1;get_min(1,1,cnt2,a[i].y+1,cnt2);
                if (flag) get_sum(cnt1,a[i].x+1,p+1,q-1);
                else get_sum(a[i].x-1,1,p+1,q-1);
            }
            fo(i,left,right) modify(1,1,cnt2,a[i].y);
        }
        for(int x=1;x<=cnt2;x=q+1) {
            q=cnt2+1;
            get_min(1,1,cnt2,x,cnt2);
            get_sum(cnt1,1,x,q-1);
        }
        fo(i,l,r) revoke(1,1,cnt2,a[i].y);
    }
}
int main() {
    for(ty=read();ty;ty--) {

        n=read();k=read();ans=0;
        memset(bz,0,sizeof(bz));int cnt=0;
        fo(i,1,n) {
            a[i].x=read();a[i].y=read();a[i].z=read();
            swap(a[i].x,a[i].y);
            if (!bz[a[i].z]) bz[a[i].z]=1,cnt++;
        }
        if (cnt<k) {
            printf("%d\n",n);
            continue;
        }

        fo(i,1,n) b[i].v=a[i].x,b[i].id=i;
        sort(b+1,b+n+1,cmp);cnt1=0;
        fo(i,1,n) {
            if (i==1||b[i].v!=b[i-1].v) cnt1++;
            a[b[i].id].x=cnt1;
        }
        fo(i,1,n) b[i].v=a[i].y,b[i].id=i;
        sort(b+1,b+n+1,cmp);cnt2=0;
        fo(i,1,n) {
            if (i==1||b[i].v!=b[i-1].v) cnt2++;
            a[b[i].id].y=cnt2;
        }

        memset(last,0,sizeof(last));num=0;
        fo(i,1,n) link(a[i].x,i);
        prepare();

        sort(a+1,a+n+1,cmp1);
        solve(0);
        fo(i,1,n/2) swap(a[i],a[n-i+1]);
        solve(1);

        printf("%d\n",ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值