BZOJ3658: Jabberwocky

9 篇文章 0 订阅
4 篇文章 0 订阅

题目大意:平面上给出n个点,每个点有一个颜色,你可以选择一条线段以上或以下的所有点,并且这些点不能包含所有颜色,问最多能选多少点

假设找一条线段以下的

首先我们可以按y坐标排序,然后假设这条线段所在直线在最高处,这时答案等于相邻两个相同颜色之间的最大间隔点数

然后当这条线段所在直线逐渐下移时,相当于逐渐删掉这些点,每删掉一个就用这个点之前相邻的和之后相邻的之间的点数更新一下答案

这一步可以用链表+树状数组完成

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define N 100010
using namespace std;
struct ppp{long long x,y,c,num;}a[N];
bool cmpx(ppp x,ppp y){return x.x<y.x;}
bool cmpy(ppp x,ppp y){return x.y<y.y;}
long long bef[N],nxt[N],pre[N];
long long ax[N];
long long cntx,cnty;
long long X[N],Y[N];
long long c[N];
map<int,int>p;
void change(long long x,long long v)
{
	for(;x<=cntx;x+=x&-x)
	c[x]+=v;
}
long long check(long long x)
{
	long long ret=0;
	for(;x;x-=x&-x)
	ret+=c[x];
	return ret;
}
void del(long long x)
{
	bef[nxt[x]]=bef[x];
	nxt[bef[x]]=nxt[x];
}
void doit()
{
	cntx=0;cnty=0;
	memset(pre,0,sizeof(pre));
	long long n,k;
	scanf("%lld%lld",&n,&k);
	long long i,j,x,y,l;
	for(i=1;i<=n;i++)
	{
		scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].c);
		a[i].num=i;
	}
	ax[0]=707185547;
	for(i=1;i<=n;i++)
	ax[i]=a[i].x;
	sort(ax+1,ax+n+1);
	for(i=1;i<=n;i++)
	if(ax[i]!=ax[i-1])
	{
		cntx++;
		p[ax[i]]=cntx;
	}
	for(i=1;i<=n;i++)
	a[i].x=p[a[i].x];
	for(i=1;i<=n;i++)
	ax[i]=a[i].y;
	sort(ax+1,ax+n+1);
	for(i=1;i<=n;i++)
	if(ax[i]!=ax[i-1])
	{
		cnty++;
		p[ax[i]]=cnty;
	}
	for(i=1;i<=n;i++)
	a[i].y=p[a[i].y];
	for(i=1;i<=n;i++)
	X[i]=a[i].x,Y[i]=a[i].y;
	sort(a+1,a+n+1,cmpx);
	for(i=1;i<=n;i++)
	{
		nxt[pre[a[i].c]]=a[i].num;
		bef[a[i].num]=pre[a[i].c];
	//	cout<<a[i].num<<' '<<bef[a[i].num]<<' '<<a[i].c<<'!'<<endl;
		pre[a[i].c]=a[i].num;
	}
	for(i=1;i<=k;i++)
	nxt[pre[i]]=n+1;
/*	for(i=1;i<=n;i++)
	cout<<a[i].num<<' '<<bef[i]<<' '<<nxt[i]<<endl;*/
	X[n+1]=cntx+1;
	long long ans=0;
	for(i=1;i<=n;i++)
	change(a[i].x,1);
	for(i=1;i<=n;i++)
	{
		ans=max(ans,check(X[nxt[i]]-1)-check(X[i]));
		ans=max(ans,check(X[i]-1)-check(X[bef[i]]));
	}
//	cout<<ans;
	sort(a+1,a+n+1,cmpy);
	j=1;
	for(i=1;i<=n;i++)
	{
		while(a[j].y==a[i].y)
		{
			change(a[j].x,-1);
		//	cout<<a[j].x<<'!';
			del(a[j].num);
			j++;
		}
		l=a[i].num;
		ans=max(ans,check(X[nxt[l]]-1)-check(X[bef[l]]));
	//	cout<<check(X[nxt[l]]-1)<<'@'<<ans<<' ';
	}
	memset(pre,0,sizeof(pre));
	sort(a+1,a+n+1,cmpx);
	for(i=1;i<=n;i++)
	{
		nxt[pre[a[i].c]]=a[i].num;
		bef[a[i].num]=pre[a[i].c];
		pre[a[i].c]=a[i].num;
	}
	for(i=1;i<=k;i++)
	{
		nxt[pre[i]]=n+1;
		if(pre[i]==0) ans=n;
	}
	X[n+1]=cntx+1;
	for(i=1;i<=n;i++)
	change(a[i].x,1);
	sort(a+1,a+n+1,cmpy);
	j=n;
	for(i=n;i>=1;i--)
	{
		while(a[j].y==a[i].y)
		{
			change(a[j].x,-1);
			del(a[j].num);
			j--;
		}
		l=a[i].num;
		ans=max(ans,check(X[nxt[l]]-1)-check(X[bef[l]]));
	}
	printf("%lld\n",ans);
}
int main()
{
	long long T;
	scanf("%lld",&T);
	while(T--)
	doit();
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值