WC模拟(1.8) T3 送你一朵圣诞树

标签: NOI 并查集 贪心
171人阅读 评论(0) 收藏 举报
分类:

送你一朵圣诞树

题目背景:

1.8 WC模拟T3

分析:并查集 +  + 贪心

 

对于全局最小的那个点,选择了它的父亲之后,就一定会选择它,所以我们直接合并它和它的父亲,那么对于一个点集i,记录ti为点集中的点的个数,Si为点集中的点的权值和,那么,对于两个点集,如果点集i优于点集j,那么ti * sj > tj * si,那么si /ti < sj / tj,那么直接并查集 + 堆,每次合并当前块和父亲的块就可以了。

 

Source:

/*
	created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>
#include <bitset>

inline char read() {
	static const int IN_LEN = 1024 * 1024;
	static char buf[IN_LEN], *s, *t;
	if (s == t) {
		t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
		if (s == t) return -1;
	}
	return *s++;
}

///*
template<class T>
inline void R(T &x) {
	static char c;
	static bool iosig;
	for (c = read(), iosig = false; !isdigit(c); c = read()) {
		if (c == -1) return ;
		if (c == '-') iosig = true;	
	}
	for (x = 0; isdigit(c); c = read()) 
		x = ((x << 2) + x << 1) + (c ^ '0');
	if (iosig) x = -x;
}
//*/

const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN], *oh = obuf;
inline void write_char(char c) {
	if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
	*oh++ = c;
}

template<class T>
inline void W(T x) {
	static int buf[30], cnt;
	if (x == 0) write_char('0');
	else {
		if (x < 0) write_char('-'), x = -x;
		for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
		while (cnt) write_char(buf[cnt--]);
	}
}

inline void flush() {
	fwrite(obuf, 1, oh - obuf, stdout);
}

/*
template<class T>
inline void R(T &x) {
	static char c;
	static bool iosig;
	for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
		if (c == '-') iosig = true;	
	for (x = 0; isdigit(c); c = getchar()) 
		x = ((x << 2) + x << 1) + (c ^ '0');
	if (iosig) x = -x;
}
//*/

const int MAXN = 30000 + 10;

struct node {
	int to, s, t;
	node(int to = 0, int s = 0, int t = 0) : to(to), s(s), t(t) {}
	inline bool operator < (const node &a) const {
		return (double)s / t > (double)a.s / a.t;
	}
} ;

std::priority_queue<node> q;
std::vector<int> edge[MAXN];

int n, x, y, val;
int w[MAXN], deg[MAXN], father[MAXN], sum[MAXN], size[MAXN], fa[MAXN];
bool able[MAXN];

inline void add_edge(int x, int y) {
	edge[x].push_back(y), edge[y].push_back(x);
}

inline void read_in() {
	R(n);
	for (int i = 1; i < n; ++i) R(x), R(y), add_edge(x, y);
	for (int i = 1; i <= n; ++i) R(w[i]), R(able[i]);
}

inline void dfs(int cur, int fa) {
	deg[cur] = 0;
	for (int p = 0; p < edge[cur].size(); ++p) {
		int v = edge[cur][p];
		if (v != fa) father[v] = cur, dfs(v, cur), deg[cur]++;
	}
}

inline int get_father(int x) {
	return (fa[x] == x) ? (x) : (fa[x] = get_father(fa[x]));
}

inline void solve() {
	long long ans = 0;
	for (int i = 1; i <= n; ++i) {
		if (able[i]) {
			dfs(i, 0);
			long long ret = 0;
			while (!q.empty()) q.pop();
			for (int j = 1; j <= n; ++j) {
				if (j != i) q.push(node(j, w[j], 1));
				sum[j] = w[j], size[j] = 1, ret += w[j], fa[j] = j;
			}
			while (!q.empty()) {
				node temp = q.top();
				int cur = q.top().to;
				q.pop();
				if (get_father(cur) != cur || size[cur] != temp.t) continue ;
				int fa = get_father(father[cur]);
//				std::cout << "cur == " << cur << " " << fa << '\n';
//				std::cout << size[cur] << " " << sum[cur] << " " << size[fa] << " " << sum[fa] << '\n';
				ret += (long long)size[fa] * sum[cur], ::fa[cur] = fa;
				size[fa] += size[cur], sum[fa] += sum[cur];
				if (fa != i) q.push(node(fa, sum[fa], size[fa]));
			}
			ans = std::max(ans, ret);
		}
	}
	std::cout << ans;
}

int main() {
	freopen("xmastree2.in", "r", stdin);
	freopen("xmastree2.out", "w", stdout);
	read_in();
	solve();
	return 0;
}


查看评论

第二类斯特林数【清华冬令营2018模拟】送你一个DAG

题目 1.1 Description 送你一个n 个点m 条边的DAG 和参数k, 定义一条经过l 条边的路径的权值为l^k. 对于i=1…n, 求出所有1 到i 的路径的权值之和, 对9982...
  • Fate_Zero_Saber
  • Fate_Zero_Saber
  • 2018-01-08 17:15:05
  • 282

[JZOJ5515] 送你一朵圣诞树

Description 给出一棵树(不超过10个点可以作为根),每个点有一个权值a 要求按照某一个顺序选完所有点,一个点必须在父亲选完以后才能选,i号点在第j个被选对答案的贡献为a[i]*j 求...
  • hzj1054689699
  • hzj1054689699
  • 2018-01-14 22:31:31
  • 166

送你一颗圣诞树

题意有mm棵树T0T_0~TmT_m,T0T_0只有一个00号节点。对于Ti(i∈[1,m])T_i(i\in[1,m]),给出ai,bi,ci,di,lia_i,b_i,c_i,d_i,l_i,表示...
  • lzxzxx
  • lzxzxx
  • 2015-09-08 16:01:42
  • 551

【五校联考1day2】送你一颗圣诞树

题目再过三个多月就是圣诞节了,小R 想送小Y 一棵圣诞树作为节日礼物。因为他想让这棵圣诞树越大越好,所以当然是买不到能够让他满意的树的,因此他打算自己把这棵树拼出来。 现在,小R 开始画这棵树的设计...
  • xieguofu2014
  • xieguofu2014
  • 2016-01-24 16:53:23
  • 511

[JZOJ5513] 送你一棵圣诞树2

Description 给出一棵N个点的树 在树上进行随机点分治,每个节点需要你确定一个不超过K的权值,点分树上的父亲的权值严格小于儿子的。 问有多少种不同的结果,两种结果不同当且...
  • hzj1054689699
  • hzj1054689699
  • 2018-01-09 21:21:39
  • 117

送你一朵圣诞树

#include #include #include #include #include #include #define fo(i,a,b) for(i=a;i #define db double ...
  • Fate_Zero_Saber
  • Fate_Zero_Saber
  • 2018-01-11 08:11:05
  • 184

[JZOJ5512] 送你一棵圣诞树

Description 一棵 n 个点的树, 树根为 1. 一开始每个点上有一个 1…n 的颜色 ci, 不同点颜色可以相同. 现在有 q 次操作, 分为两种类型: • 1 u l r:...
  • hzj1054689699
  • hzj1054689699
  • 2018-01-09 12:21:08
  • 248

WC模拟(1.6) T3 送你一棵圣诞树

状压DP + 子集枚举
  • scar_lyw
  • scar_lyw
  • 2018-01-11 15:51:28
  • 110

【清华冬令营2018模拟】送你一棵圣诞树

Description 送你一棵n 个点的树, 树根为1. 一开始每个点上有一个1:::n 的颜色ci, 不同点颜色可以相同. 现在有q 次操作, 分为两种类型: • 1 u l r: 询问子树...
  • u011056504
  • u011056504
  • 2018-01-08 21:24:30
  • 282

WC模拟(1.8) T2 送你一个集合

二进制
  • scar_lyw
  • scar_lyw
  • 2018-01-11 15:59:55
  • 187
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 2万+
    积分: 2169
    排名: 2万+
    博客专栏
    最新评论