[jzoj 3301] 【集训队互测2013】家族 {并查集}

题目

Description
阿狸和桃子养了n 个小阿狸, 小阿狸们每天都在一起玩的很开心. 作为工程师的阿狸在对小阿狸们之间的关系进行研究以后发现了小阿狸的人际关系由某种神奇的相互作用决定, 阿狸称之为“键”. 每个键有一个频率, 称为键频率, 是一个整数(单位Hz)。

由于小阿狸们每天成集团地黏在一起, 桃子希望他们能够分成更加独立的几团. 阿狸发现, 一旦小阿狸们分开, 独立的一块连在一起的几个小阿狸就会形成一个家族, 而家族的类型由这个家族的小阿狸的数量唯一确定(比如说只有一个小阿狸的家族显然就是单身码农, 两个小阿狸的显然是一对小阿狸恋人, 三个小阿狸的就是三口之家等等). 显然, 一个小阿狸和另一个小阿狸处于同一家族,当且仅当两个小阿狸之间存在直接或间接的键组成的路径.。

桃子对每种小阿狸家族都有自己的喜好程度, 她希望所有的小阿狸家族喜好程度之和大于等于K。

为了让小阿狸们分开来, 阿狸决定让某些键断裂, 只保留某一段频率的键,比如说100Hz 到140Hz 频率的键, 这时频段宽度为40Hz. 当然, 阿狸希望频段宽度越小越好, 但至少要有一个小键. 你的任务就是求出最小的频段宽度.

注意, 输入不保证全部键都有效时只有一个小阿狸家族。

Input
第一行3 个整数n(<=1000), m(<=5000), K(0~2^31-1)。

接下来1 行n 个整数, 第i 个整数表示桃子对大小为i 的小阿狸家族的喜爱程度。

接下来m 行, 每行3 个整数, u, v, f. 表示u 小阿狸和小阿狸v 之间存键, 频率f Hz。

Output
一个整数, 即最窄的频段宽度(不存在可行频段, 输出"T_T", 不含引号).


解题思路

固定左端点,暴力枚举右端点,显然超时。

离散化以后不难发现其实本质不同的频段只有 O(m^2)个, 我们必须在 O(1)的时间之内求出
每个频段的喜爱程度.
如果我们枚举频段下界, 然后上界从下界开始不断增加, 每次实际上加入了一个或多个权值
相同的键. 别忘了我们必须维护加入一个键以后的喜爱程度.
利用并查集, 加入键(u, v)时, 我们只需要减去原来 u, v 所在家族的喜爱程度, 加上 u, v 新形
成的家族的喜爱程度.
并查集必须维护每个不相交的集合的大小才能完成这个维护.


代码

#include<cstdio>
#include<algorithm>
#include<string>
#include<queue>
#include<cstring>
#define rep(i,x,y) for (register int i=x;i<=y;++i)
using namespace std; 
const int N=1e3+10; 
int n,m,k,a[N],fa[N],siz[N],cost; long long ans=1e18; 
struct node{int x,y,z;}b[N*10]; 
inline bool cmp(node x,node y){return x.z<y.z;}
inline int find(int x){return (x==fa[x])?x:find(fa[x]);}
void co(int x,int y){if (x<y) fa[y]=x,siz[x]+=siz[y]; else fa[x]=y,siz[y]+=siz[x];}
int main(){
	scanf("%d%d%d",&n,&m,&k); 
	rep(i,1,n) scanf("%d",&a[i]); 
	rep(i,1,m) {
		int x,y,z; 
		scanf("%d%d%d",&x,&y,&z); 
		b[i]=(node){x,y,z}; 	
	}
	sort(b+1,b+m+1,cmp); 
	rep(i,1,m){
		cost=a[1]*n; 
		rep(j,1,n) fa[j]=j,siz[j]=1; 
		rep(j,i,m) {
			int x=find(b[j].x),y=find(b[j].y); 
			if (x==y) continue; 
			cost+=a[siz[x]+siz[y]]-a[siz[x]]-a[siz[y]]; 
			co(x,y); 
			if (b[j].z-b[i].z>ans) break; 
			if (b[j].z!=b[j+1].z&&cost>=k) {ans=b[j].z-b[i].z; break;}
		}
	}
	if (ans==1e18) printf("T_T"); else printf("%lld",ans); 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值