CF1923(重要)

只做了 A,成功被 sb 错误卡住。

A

每次挑最右边的左移。

B

每次一定是优先向最近的怪物打,打完一个打下一个最近的。

子弹不一定只能打两个怪物,所以打的时候用循环判断子弹是否打完。

C

  1. l = r 不行

  2. 否则考虑全 1 再把所有 \(c_i=1\) 的都 +1,这需要 \(cnt1[r]-cnt1[l-1]+(r-l+1)\)\(cnt1[i]\) 表示前 \(i\) 个中 \(1\) 的个数。

    如果 \(s[r]-s[l-1]<\text{上面的式子}\),就可以放下;否则就是不能。

    注意是 \(<\) 不是 \(\le\)

D

先对于每个位置求出 \(l,r\)\(l[i]\) 表示与 \(a_i\) 相等的数字段左端点在哪里,\(r[i]\) 表示右端点。

对一个位置 \(x\) 的答案分成两类:它左边的吃掉它和它右边的吃掉它,这两类是类似的。

对于它左边的吃掉它,我们先二分一个位置 \(pos\)\(pos\) 是最大的使得 \(a_pos+\dots+a_{x-1}>a_x\) 的位置。

如果 \(pos\sim x-1\) 不是全相等,那就可以用 \(x-pos\) 次吃掉。

如果 \(1\sim x-1\) 全相等,则“它左边的吃掉它”这一类无解。

否则就是 \(l[pos]\sim x-1\) 都是相等的,所以让 \(a_{l[pos]}\) 吃掉 \(a_{l[pos]-1}\) 再一路吃过去。

E

void srh(int v, int fa) {
	int u = cntc[c[v]], s = up[c[v]];
	ans += s;
	for (int i = 0; i < e[v].size(); i++) {
		if (e[v][i] == fa)
			continue;
		up[c[v]] = 0;
		srh(e[v][i], v);
	}
	ans += cntc[c[v]] - u;
	cntc[c[v]] = u + 1;
	up[c[v]] = s + 1;
}

\(c[x]\) 表示 \(x\) 的颜色,\(cntc[clr]\) 记录当前有多少个已经回溯了的 \(clr\) 色的点上方没有已经回溯的 \(clr\) 色的点,\(up[clr]\) 表示当前有多少个 已经回溯了的 是\(clr\)色的 上方没有\(clr\)色的 不在\(v\)子树中的 结点。

代码解释:

ans += cntc[c[v]] - u\(u\) 是没遍历这颗子树时“裸露”的 \(c[v]\) 个数,\(cntc[c[v]]\) 是现在“裸露”的 \(c[v]\) 个数,所以 \(cntc[c[v]]-u\) 就是这颗子树内有多少个裸露的 \(c[v]\),都可以与 \(v\) 组成好路径。

ans += s,这些兄弟结点与当前节点都能组成好路径。

up[c[v]] = 0 是因为马上我们就要递归进子节点了,因为对于 \(v\) 的子节点 \(s\) 来说,所有 \(s\) 的颜色为 \(clr\) 的兄弟结点都不是“裸露”着的了,于是 \(up\) 改为 \(0\)

posted @ 2024-02-24 08:59  FLY_lai  阅读(27)  评论(0编辑  收藏  举报