题目

【分治】distance_题组
n<=1e5

思路

60% 由于图上只有两种颜色,分别求出凸包然后明科夫斯基差后求出最远点
即可
100% 现在有多种颜色,就比较难办了,不过我们可以对于颜色进行分治,
假设现在的序列为 ,现在先求 unique ,
则给这些颜色随便编号 ,将这n个点分成两个集合 和 :颜色
为 的放在集合 里,其他放在 里,这样, 和 中分别选
出一个点来,他们的颜色都是不同的,因此就可以像60%那样当做两种颜色
的情况来做。之后再递归处理 , 即可。

代码

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<ll,ll> node_data;
typedef vector<node_data> hull_data;

const ll MAX=1ll<<40;
const double phi=acos(-1);

template <typename Type> void read_int (Type &a) {
	char c=getchar(); bool f=false; a=0;
	while ((c<'0'||c>'9')&&c!='-') c=getchar();
	if (c=='-') f=true,c=getchar();
	while (c>='0'&&c<='9') a=(a<<1)+(a<<3)-48+c,c=getchar();
	if (f) a=-a; return;
}

int n,left[250003],right[250003],num; ll ans;

struct node {
	ll x,y,col;
	double radian;
} d[250003];

bool cmp1 (const node &a,const node &b)
	{ return a.col<b.col; }

bool cmp2 (const node &a,const node &b)
	{ return a.radian<b.radian; }

hull_data hull[1000003];

bool better (node_data a,node_data b,node_data c) {
	if ((b.first-a.first)*(c.second-b.second)-(c.first-b.first)*(b.second-a.second)<=0)
		return true;
	return false;
}

void solve (int num1,int num2,hull_data&ans) {
	
	ans.clear();
	
	ll x=MAX,y=MAX,o;
	for (int i=left[num1];i<=right[num2];i++)
		if (d[i].y<y||d[i].y==y&&d[i].x<x)
			x=d[i].x,y=d[i].y,o=i;
	std::swap(d[left[num1]],d[o]);
	for (int i=left[num1]+1;i<=right[num2];i++)
		d[i].radian=atan2(d[i].y-d[left[num1]].y,d[i].x-d[left[num1]].x);
	std::sort(d+left[num1],d+right[num2]+1,cmp2);
	
	for (int i=left[num1];i<=right[num2];i++) {
		if (ans.size()<2) { ans.push_back(node_data(d[i].x,d[i].y)); continue; }
		while (ans.size()>=2) {
			node_data last1=ans[ans.size()-1],last2=ans[ans.size()-2];
			if (!better(last2,last1,node_data(d[i].x,d[i].y))) break;
			ans.pop_back();
		} ans.push_back(node_data(d[i].x,d[i].y));
	}
	if (ans.size()>2&&better(ans[ans.size()-2],ans[ans.size()-1],ans[0]))
		ans.erase(--(--ans.end()));
	
	return;
}

void print (hull_data&value) {
	for (auto iter=value.begin();iter!=value.end();iter++)
		printf("%d %d\n",iter->first,iter->second);
	puts("~");
	return;
}

ll calc_dis (node_data value)
	{ return value.first*value.first+value.second*value.second; }

hull_data operator - (const hull_data &val) {
	static hull_data ans;
	ans=val;
	for (auto iter=ans.begin();iter!=ans.end();iter++)
		iter->first=-iter->first,
		iter->second=-iter->second;
	return ans;
}

hull_data::iterator operator + (hull_data::iterator iter,int size)
	{ auto ans=iter; while (size--) ++ans; return ans; }

hull_data calc (hull_data a,hull_data b) {
	
	static hull_data ans; ans.clear();
	
	ll x=MAX,y=MAX; hull_data::iterator o1,o2;
	for (auto iter=a.begin();iter!=a.end();iter++)
		if (iter->second<y||iter->second==y&&iter->first<x)
			x=iter->first,y=iter->second,o1=iter;
	x=MAX; y=MAX;
	for (auto iter=b.begin();iter!=b.end();iter++)
		if (iter->second<y||iter->second==y&&iter->first<x)
			x=iter->first,y=iter->second,o2=iter;
	
//	print(a); print(b);
	
	ans.push_back(node_data(o2->first+o1->first,o2->second+o1->second));
	auto p1=o1,p2=o2,n1=o1+1,n2=o2+1;
	int len1=a.size(),len2=b.size();
	if (n1==a.end()) n1=a.begin();
	if (n2==b.end()) n2=b.begin();
	double r1=atan2(n1->second-p1->second,n1->first-p1->first);
	if (r1<0) r1+=2*phi;
	double r2=atan2(n2->second-p2->second,n2->first-p2->first);
	if (r2<0) r2+=2*phi;
	
	while (len1+len2>1) {
		if (len1&&(!len2||r1<r2)) {
			--len1; node_data next(ans[ans.size()-1].first+n1->first-p1->first,ans[ans.size()-1].second+n1->second-p1->second);
			while (ans.size()>=2) {
				node_data last1=ans[ans.size()-1],last2=ans[ans.size()-2];
				if (!better(last2,last1,next)) break;
				ans.pop_back();
			} ans.push_back(next);
			p1=n1; ++n1;
			if (n1==a.end()) n1=a.begin();
			r1=atan2(n1->second-p1->second,n1->first-p1->first);
			if (r1<0) r1+=2*phi;
		} else {
			--len2; node_data next(ans[ans.size()-1].first+n2->first-p2->first,ans[ans.size()-1].second+n2->second-p2->second);
			while (ans.size()>=2) {
				node_data last1=ans[ans.size()-1],last2=ans[ans.size()-2];
				if (!better(last2,last1,next)) break;
				ans.pop_back();
			} ans.push_back(next);
			p2=n2; ++n2;
			if (n2==b.end()) n2=b.begin();
			r2=atan2(n2->second-p2->second,n2->first-p2->first);
			if (r2<0) r2+=2*phi;
		}
	}
	
	if (ans.size()>2&&better(ans[ans.size()-2],ans[ans.size()-1],ans[0]))
		ans.erase(--(--ans.end()));
	
	return ans;
}

void divide (int now,int left,int right) {
	
	if (left==right) { solve(left,right,hull[now]); return; }
	int mid=left+right>>1;
	divide(now<<1,left,mid); divide(now<<1|1,mid+1,right);
	
	if (hull[now<<1].size()>=3&&hull[now<<1|1].size()>=3) {
		hull[now]=calc(hull[now<<1],-hull[now<<1|1]);
		for (auto iter=hull[now].begin();iter!=hull[now].end();iter++)
			ans=std::max(ans,calc_dis(*iter));
//		print(hull[now]);
	} else {
		for (auto iter1=hull[now<<1].begin();iter1!=hull[now<<1].end();iter1++)
			for (auto iter2=hull[now<<1|1].begin();iter2!=hull[now<<1|1].end();iter2++)
				ans=std::max(ans,calc_dis(node_data(iter1->first-iter2->first,iter1->second-iter2->second)));
	}
	
	solve(left,right,hull[now]);
	
	return;
}

int main () {
	
	read_int(n);
	for (int i=1;i<=n;i++)
		read_int(d[i].x),read_int(d[i].y),
		read_int(d[i].col);
	std::sort(d+1,d+n+1,cmp1);
	
	int point=1,tail;
	while (point<=n) {
		tail=point;
		while (tail<n&&d[tail+1].col==d[point].col)
			++tail;
		++num; left[num]=point; right[num]=tail;
		for (int i=point;i<=tail;i++)
			d[i].col=num;
		point=tail+1;
	}
	
	divide(1,1,num);
	printf("%lld",ans);
	
	return 0;
}