BZOJ 2139 road

BZOJ 2139 road

题目传送门1

题意

很久很久以前,中原地区分成了N个国家,编号为1到N,任意两个国家都可互达。每个国家有一个攻击值\(A[i]\)和防御值\(B[i]\)。定义一个人从i国去j国的危险值为:假如\(A[i]>B[j]\),则危险值为\(( A[i]^2-B[j]^2)\),否则危险值为0。现在,Nan从国家1出发,经过每一个国家有且仅有一次,最后回到国家1,要求找出一种方案,使得其中危险值的最大值最小。

题解

感觉网上的题解好少啊,实际上想通了似乎发现这题还是比较的好写的,不过仍然还是一道十分妙妙的题目。在看到我们现将所有国家的\(a\)\(b\)开来,然后我们分别按他们的值从小到大排序,然后先贪心的进行连边。这个时候,我们的连边方式一定是从\(a_i\)属于的那个国家连向\(b_i\)属于的那个国家,因为这样可以保证连出来的边危险值的最大值最小(这个可以意会一下)。这样我们就会得到许多小环,然后我们的目的就是把这些小环连成一个大环。所以我们考虑在这些环上加边,由于我们还要保证环之间的边能够尽量的小,所以我们在环之间的边一定是从\(a_i\)属于的那个国家连向\(b_{i-1}\)属于的那个国家(因为如果连向\(b_{i+1}\)所属的国家的话,那么\(a_n\)连向的国家一定是\(b_1\)所属的国家,那样就没有之前那种方案连那么优了)知道这个之后我们就可以对这些环做最小生成树了,每次连边的时候更新一下答案就行了,复杂度为\(O(nlogn)\)

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
#define PAUSE printf("Press Enter key to continue..."); fgetc(stdin);
const int N=1e6+500;
const int Md=32767;
struct country {
	int idx,v;
	bool operator < (const country &rhs) const {
		return v<rhs.v;
	}
}a[N],b[N],c[N];
int n,x,y,z;
int fa[N];
int ans;
/*==================Define Area================*/
int Find(int x) {return fa[x]==x?x:fa[x]=Find(fa[x]);}
int Sqr(int x) {return x*x;}

int main() {
	read(n);
	read(a[1].v);read(a[2].v);read(x);read(y);read(z);
	for(int i=3;i<=n;i++) a[i].v=((ll)x*a[i-1].v+(ll)y*a[i-2].v+z)%Md;
	read(b[1].v);read(b[2].v);read(x);read(y);read(z);
	for(int i=3;i<=n;i++) b[i].v=((ll)x*b[i-1].v+(ll)y*b[i-2].v+z)%Md;
	for(int i=1;i<=n;i++) fa[i]=a[i].idx=b[i].idx=i;
	sort(a+1,a+1+n);sort(b+1,b+1+n);
	for(int i=1;i<=n;i++) {
		ans=max(ans,Sqr(a[i].v)-Sqr(b[i].v));
		fa[Find(a[i].idx)]=Find(b[i].idx);
	}
	for(int i=2;i<=n;i++) {
		c[i].v=Sqr(a[i].v)-Sqr(b[i-1].v);c[i].idx=i;
	}
	sort(c+1,c+n);
	for(int i=1;i<n;i++) {
		int fx=Find(a[c[i].idx].idx),fy=Find(b[c[i].idx-1].idx);
		if(fx!=fy) ans=max(ans,c[i].v),fa[fx]=fy;
	}
	printf("%d\n",ans);
	return 0;
}
posted @ 2018-09-02 16:18  Apocrypha  阅读(256)  评论(0编辑  收藏  举报