Description
有 N 个彩色糖果在平面上。小奇想在平面上取一条水平的线段,并拾起它上方或下方的所有糖果。求出最多能够拾起多少糖果,使得获得的糖果并不包含所有的颜色。
Solution1
指向【一大堆常犯的错误、提醒和公式】的第20条;
枚举每个颜色,把向上取和向下取分开讨论,
对于向上取,显然是先找最高的,把它以上的其他颜色点取完,再向这个点在坐标中位置的左边右边分治下去,
这个用主席树即可,
复杂度:
O(nlog(n))
(常数很大啊)
注意优化:当发现就算把当前区间的点取完也不能使Ans更优,直接退出
Solution2
同样枚举每个颜色I,不同的是,这里像是上面分治倒着做,同样把向上取和向下取分开讨论,
对于向上取,维护扫描线,枚举颜色I,每个颜色为I的点,记录他当前左、右边的第一个点,那么它的答案就是这个区间的所有点(不包当前行),
Code
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
using namespace std;
const int N=100050;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,Ans,R,TOP;
int px[N],py[N];
struct qqww
{
int x,y,k;
}a[N];
struct qwqw
{
int l,r,mx,mx1,mi,mi1;
}b[N*30];
int root[N],b0;
struct qwqwH
{
int l,r,v,ti;
}bH[N*30];
int rootH[N],bH0;
int rsum[N];
bool zk[N],TI;
bool PXx(int q,int w){return a[q].x<a[w].x;}
bool PXy(int q,int w){return a[q].y<a[w].y;}
int build(int l,int r,int e,int l1,int l2)
{
if(!e)
{
e=++b0;
b[e].mx=-2e9;b[e].mi=2e9;
b[e].mx1=b[e].mi1=b[e].l=b[e].r=0;
}
if(l==r)
{
b[e].mx=max(b[e].mx,l2);
b[e].mi=min(b[e].mi,l2);
b[e].mx1=b[e].mi1=l;
return e;
}
int t=(l+r)>>1;
if(l1<=t)b[e].l=build(l,t,b[e].l,l1,l2);
else b[e].r=build(t+1,r,b[e].r,l1,l2);
if(b[b[e].l].mx>b[b[e].r].mx)b[e].mx=b[b[e].l].mx,b[e].mx1=b[b[e].l].mx1;
else b[e].mx=b[b[e].r].mx,b[e].mx1=b[b[e].r].mx1;
if(b[b[e].l].mi<b[b[e].r].mi)b[e].mi=b[b[e].l].mi,b[e].mi1=b[b[e].l].mi1;
else b[e].mi=b[b[e].r].mi,b[e].mi1=b[b[e].r].mi1;
return e;
}
int buildH(int l,int r,int e1,int e,int I,int l1)
{
if(!e||bH[e].ti<I)
{
e=++bH0;
bH[e].l=bH[e1].l;
bH[e].r=bH[e1].r;
bH[e].v=bH[e1].v;
bH[bH0].ti=I;
}
if(l==r){bH[e].v++;return e;}
int t=(l+r)>>1;
if(l1<=t)bH[e].l=buildH(l,t,bH[e1].l,bH[e].l,I,l1);
else bH[e].r=buildH(t+1,r,bH[e1].r,bH[e].r,I,l1);
bH[e].v=bH[bH[e].l].v+bH[bH[e].r].v;
return e;
}
int fmx,fmx1,fmi,fmi1;
void find(int l,int r,int e,int l1,int r1)
{
if(!e||l>r||l1>r1)
{
fmx=b[0].mx;fmx1=b[0].mx1;
fmi=b[0].mi;fmi1=b[0].mi1;
return;
}
if(l>=l1&&r<=r1)
{
fmx=b[e].mx;fmx1=b[e].mx1;
fmi=b[e].mi;fmi1=b[e].mi1;
return;
}
int t=(l+r)>>1;
if(r1<=t)find(l,t,b[e].l,l1,r1);
else if(t<l1)find(t+1,r,b[e].r,l1,r1);
else
{
find(l,t,b[e].l,l1,t);
int qmx=fmx,qmx1=fmx1,qmi=fmi,qmi1=fmi1;
find(t+1,r,b[e].r,t+1,r1);
if(fmx<qmx)fmx=qmx,fmx1=qmx1;
if(fmi>qmi)fmi=qmi,fmi1=qmi1;
}
}
int findH(int l,int r,int e1,int e,int l1,int r1)
{
if(!e||l1>r1||l>r)return 0;
if(l>=l1&&r<=r1)return bH[e].v-bH[e1].v;
int t=(l+r)>>1;
if(r1<=t)return findH(l,t,bH[e1].l,bH[e].l,l1,r1);
if(t<l1)return findH(t+1,r,bH[e1].r,bH[e].r,l1,r1);
return findH(l,t,bH[e1].l,bH[e].l,l1,t)+findH(t+1,r,bH[e1].r,bH[e].r,t+1,r1);
}
void divideU(int I,int l,int r)
{
if(l>r)return;
if(rsum[r]-rsum[l-1]<=Ans)return;
find(1,R,root[I],l,r);
int qmx1=fmx1;
Ans=max(Ans,findH(1,TOP,rootH[l-1],rootH[r],fmx+1,TOP));
if(qmx1)divideU(I,l,qmx1-1),divideU(I,qmx1+1,r);
}
void divideD(int I,int l,int r)
{
if(l>r)return;
if(rsum[r]-rsum[l-1]<=Ans)return;
find(1,R,root[I],l,r);
int qmi1=fmi1;
Ans=max(Ans,findH(1,TOP,rootH[l-1],rootH[r],1,fmi-1));
if(qmi1)divideD(I,l,qmi1-1),divideD(I,qmi1+1,r);
}
int main()
{
int _;b[0].mx=-2e9;b[0].mi=2e9;
read(_);
while(_--)
{
read(n),read(m);
Ans=0;b0=bH0=0;
fo(i,1,m)root[i]=0;
TI++;
fo(i,1,n)read(a[i].x),read(a[i].y),zk[read(a[i].k)]=TI,px[i]=py[i]=i;
fo(i,1,m)if(zk[i]<TI)m=0;
if(!m){printf("%d\n",n);continue;}
sort(px+1,px+1+n,PXx);
sort(py+1,py+1+n,PXy);
R=TOP=1;a[0].x=a[0].y=2333333;
fo(i,1,n)
{
int w=R;
if(a[px[i+1]].x!=a[px[i]].x&&i<n)R++;
a[px[i]].x=w;rsum[w]++;
w=TOP;
if(a[py[i+1]].y!=a[py[i]].y&&i<n)TOP++;
a[py[i]].y=w;
}
fo(i,1,R)rootH[i]=0,rsum[i]+=rsum[i-1];
fo(i,1,n)
{
root[a[i].k]=build(1,R,root[a[i].k],a[i].x,a[i].y);
rootH[a[px[i]].x]=buildH(1,TOP,rootH[a[px[i]].x-1],rootH[a[px[i]].x],a[px[i]].x,a[px[i]].y);
}
fo(i,1,m)divideU(i,1,R),divideD(i,1,R);
printf("%d\n",Ans);
fo(i,1,R)rsum[i]=0;
}
return 0;
}