题目描述:
平面上有n个点,每个点有k种颜色中的一个。
你可以选择一条水平的线段获得在其上方或其下方的所有点,如图所示:
请求出你最多能够得到多少点,使得获得的点并不包含所有的颜色。
n,k<=100000
题目分析:
不包含所有的颜色
→
\rarr
→ 保证一种颜色不选,其它任意
考虑两个颜色相同的横坐标相邻的点
(
x
0
,
y
0
)
(x_0,y_0)
(x0,y0)和
(
x
1
,
y
1
)
(x_1,y_1)
(x1,y1),那么横坐标在
[
x
0
+
1
,
x
1
−
1
]
[x_0+1,x_1-1]
[x0+1,x1−1]的点就可以全部得到。
这时候相当于选择的线段无限低,选择它上方的点。
把这条线往上,一次删除一行,删除的时候一个点的时候找到它上方的跟它颜色相同的前驱 p r e pre pre和后继 n e x t next next(没有就是0和n+1),计算 [ p r e + 1 , n e x t − 1 ] [pre+1,next-1] [pre+1,next−1]之间的点数(这条线下方的点已经删掉了)。
所以就是维护前驱后继,统计区间点数。
前者可以用双向链表(先链起来,删除点的时候把它的pre和next接上)或者动态开点线段树。 后者可以树状数组。
Code:
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define maxn 100005
#define LL long long
using namespace std;
inline void read(int &a){
char c;bool f=0;
while(!isdigit(c=getchar())) if(c=='-') f=1;
for(a=c-'0';isdigit(c=getchar());a=a*10+c-'0');
if(f) a=-a;
}
int T,n,m,pre[maxn],nxt[maxn],last[maxn],ans,X[maxn];
int arr[maxn];
struct node{
int x,y,c,id;
}a[maxn];
bool cmpx(const node &a,const node &b){return a.x<b.x;}
bool cmpy(const node &a,const node &b){return a.y<b.y;}
void update(int i,int d){for(;i<=n;i+=i&-i) arr[i]+=d;}
int getsum(int i){int s=0;for(;i;i-=i&-i) s+=arr[i];return s;}
inline void calc(int l,int r){if(l<=r) ans=max(ans,getsum(r)-getsum(l-1));}
void solve(){
memset(arr,0,sizeof arr);
memset(last,0,sizeof last);
for(int i=1;i<=n;i++){
update(X[a[i].id=i]=a[i].x,1);
pre[i]=last[a[i].c],nxt[i]=n+1;
if(pre[i]) nxt[pre[i]]=i;
last[a[i].c]=i;
calc(X[pre[i]]+1,X[i]-1);
}
X[n+1]=n+1;
for(int i=1;i<=m;i++) calc(X[last[i]]+1,n);
sort(a+1,a+1+n,cmpy);
for(int i=1,j=1;i<=n;i=j){
while(j<=n&&a[j].y==a[i].y) update(a[j++].x,-1);
for(int k=i;k<j;k++){
int o=a[k].id;
nxt[pre[o]]=nxt[o];
pre[nxt[o]]=pre[o];
calc(X[pre[o]]+1,X[nxt[o]]-1);
}
}
}
int main()
{
read(T);
while(T--){
read(n),read(m),ans=0;
for(int i=1;i<=n;i++) read(a[i].x),read(a[i].y),read(a[i].c);
int cur=1;
sort(a+1,a+1+n,cmpx);
for(int i=1;i<=n;i++){
a[i].x=cur;
if(a[i+1].x!=a[i].x) cur++;
}
solve();
for(int i=1;i<=n;i++) a[i].y=-a[i].y;
sort(a+1,a+1+n,cmpx);
solve();
printf("%d\n",ans);
}
}