首页 > 其他分享 >AtCoder Beginner Contest 302 Ex Ball Collector

AtCoder Beginner Contest 302 Ex Ball Collector

时间:2023-05-22 09:22:58浏览次数:45  
标签:AtCoder Ball Beginner sz int Contest long maxn ans

洛谷传送门

AtCoder 传送门

考虑如果只询问一次怎么做。连边 \((a_i, b_i)\),对于每个连通块分别考虑。这是 ARC111B,如果一个连通块是树,肯定有一个点不能被选;否则有环,一定能构造一种方案,使得每个点都被选。

那么现在对于每个点都要求,考虑 dfs 时合并当前的 \((a_u, b_u)\),并且使用可撤销并查集。具体而言,把每次的修改都压进栈里,退出一个点就把这些修改全部复原。注意不要路径压缩,使用按秩合并。

code
// Problem: Ex - Ball Collector
// Contest: AtCoder - TOYOTA MOTOR CORPORATION Programming Contest 2023#2 (AtCoder Beginner Contest 302)
// URL: https://atcoder.jp/contests/abc302/tasks/abc302_h
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 200100;

int n, a[maxn], b[maxn], fa[maxn], rnk[maxn], sz[maxn], e[maxn], top, ans, c[maxn];
pair<int*, int> stk[maxn * 50];
vector<int> G[maxn];

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

inline void merge(int x, int y) {
	x = find(x);
	y = find(y);
	stk[++top] = make_pair(&ans, ans);
	if (x == y) {
		ans -= (e[x] == sz[x] - 1 ? sz[x] - 1 : sz[x]);
		stk[++top] = make_pair(e + x, e[x]);
		++e[x];
		ans += (e[x] == sz[x] - 1 ? sz[x] - 1 : sz[x]);
		return;
	}
	ans -= (e[x] == sz[x] - 1 ? sz[x] - 1 : sz[x]);
	ans -= (e[y] == sz[y] - 1 ? sz[y] - 1 : sz[y]);
	if (rnk[x] <= rnk[y]) {
		stk[++top] = make_pair(fa + x, fa[x]);
		fa[x] = y;
		stk[++top] = make_pair(sz + y, sz[y]);
		sz[y] += sz[x];
		stk[++top] = make_pair(e + y, e[y]);
		e[y] += e[x] + 1;
		ans += (e[y] == sz[y] - 1 ? sz[y] - 1 : sz[y]);
		if (rnk[x] == rnk[y]) {
			stk[++top] = make_pair(rnk + y, rnk[y]);
			++rnk[y];
		}
	} else {
		stk[++top] = make_pair(fa + y, fa[y]);
		fa[y] = x;
		stk[++top] = make_pair(sz + x, sz[x]);
		sz[x] += sz[y];
		stk[++top] = make_pair(e + x, e[x]);
		e[x] += e[y] + 1;
		ans += (e[x] == sz[x] - 1 ? sz[x] - 1 : sz[x]);
	}
}

inline void undo() {
	*stk[top].fst = stk[top].scd;
	--top;
}

void dfs(int u, int fa) {
	int lsttop = top;
	merge(a[u], b[u]);
	c[u] = ans;
	for (int v : G[u]) {
		if (v == fa) {
			continue;
		}
		dfs(v, u);
	}
	while (top > lsttop) {
		undo();
	}
}

void solve() {
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) {
		scanf("%d%d", &a[i], &b[i]);
		fa[i] = i;
		rnk[i] = sz[i] = 1;
	}
	for (int i = 1, u, v; i < n; ++i) {
		scanf("%d%d", &u, &v);
		G[u].pb(v);
		G[v].pb(u);
	}
	dfs(1, -1);
	for (int i = 2; i <= n; ++i) {
		printf("%d ", c[i]);
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:AtCoder,Ball,Beginner,sz,int,Contest,long,maxn,ans
From: https://www.cnblogs.com/zltzlt-blog/p/17419720.html

相关文章

  • 【题解】Atcoder ABC302 F,G,Ex
    完全不会G和Ex,这些套路还是要积累一下的。F.MergeSet题目描述:给定\(n\)个集合,每次可以合并两个有交的集合,问最少多少次合并可以让\(1\)和\(m\)位于同一个集合中。题目分析:一开始将题读成了将\([1,m]\)位于同一个集合中,然后就感觉这个题相当不可做。因为集合的元......
  • AtCoder Regular Contest 130 E Increasing Minimum
    这题太神仙了吧!感觉还不是很懂,但是尽力理一下思路。设\(t_x\)为最大的\(j\)使得\(i_j=x\),不存在则\(t_x=0\)。设\(1\simn\)的数按照\(t\)从小到大排序后是\(p_1,p_2,...,p_n\),设\(q_i\)为\(i\)在\(p\)中的排名,即\(q_{p_i}=i\)。发现正着不好考虑,......
  • AtCoder Beginner Contest 302
    A-Attack(abc302a)题目大意给定怪物的血量\(a\)和你每次攻击扣除的血量\(b\),问打多少次怪物才会死。解题思路答案即为\(\lceil\frac{a}{b}\rceil=\lfloor\frac{a+b-1}{b}\rfloor\)神奇的代码#include<bits/stdc++.h>usingnamespacestd;usingLL=long......
  • AtCoder Regular Contest 130 C Digit Sum Minimization
    洛谷传送门AtCoder传送门分类讨论,但是写起来挺答辩的。首先发现我们要使进位尽量多。特判怎么重排都没有进位的情况(\(a_i+b_i<10\))。然后枚举个位选的两个数字,并且要求它们和\(\ge10\)。如果当前位两个位都有数字,那么从小到大枚举数位的和\(\in[9,18]\);如果有数字......
  • AtCoder Regular Contest 133 E Cyclic Medians
    洛谷传送门AtCoder传送门其实是套路题,但是为什么做不出来啊第一步就是经典套路。枚举\(k\),统计中位数\(>k\)的方案数,加起来就是中位数的总和。那么现在\(x_{1\simn},y_{1\simm}\)就变成了\(0/1\)序列,考虑一次操作,如果\((x,y)=(0,0)\),那么\(a\)会变成\(0\)......
  • AtCoder Regular Contest 124 F Chance Meeting
    洛谷传送门AtCoder传送门感觉挺高妙的……为了方便,不妨把横纵坐标都整体减\(1\)。如果单独考虑上下移动,方案数是\(\binom{2n}{n}\)。发现两个人上下总共移动\(n\)次后一定会在同一行,设这行编号为\(x\),那么最后带个\(\binom{n}{x}^2\)的系数,并且除掉上下移动后方案本质......
  • AtCoder Beginner Contest 212 F Greedy Takahashi
    洛谷传送门AtCoder传送门考虑每条边,因为是静态的,所以可以预处理出\(f_{i,j},g_{i,j}\)表示从第\(i\)条边,往后跳\(2^j\)条边,跳到边的编号和目前的时间(如果不存在就当作跳到第\(0\)条边)。直接倍增处理即可。询问就是找到从\(u\)开始的出边,能跳尽量跳。注意一些细节......
  • AtCoder Beginner Contest 253(E,F)
    AtCoderBeginnerContest253(E,F)E(dp,前缀和)E大意就是求满足以下要求的的序列的个数\(1\),满足\(a_i\)都在\([1,m]\)的范围里面\(2\),满足$\verta_i-a_{i+1}\vert$大于\(k\)之前做过一个类似的题目,是绝对值小于\(k\),不过大同小异这里我使用了前缀和来优化但是这里......
  • AtCoder Beginner Contest 200 F Minflip Summation
    洛谷传送门AtCoder传送门显然的策略:选择全部\(0\)段变成\(1\),或选择全部\(1\)段变成\(0\)。归纳可得一般性的结论:设字符串中\(s_i\nes_{i+1}\)的位置数为\(k\),答案为\(\left\lceil\frac{k}{2}\right\rceil\)。因为在模意义下不能上取整,考虑记\(k\)的奇偶性(这样......
  • AtCoder Regular Contest 160 D Mahjong
    洛谷传送门AtCoder传送门搞笑题,我不会做,我更搞笑。考虑逆序操作,即初始有一个全\(0\)序列,每次单点加\(k\)或者长为\(k\)区间加\(1\)。考虑把一个操作集合唯一对应到一个最终序列,不难发现只要限制每个区间加\(1\)的次数\(<k\)即可。因为如果正序操作,加上了限制,每个......