训练记录 10.10

今天不是我们的题啊,是提高组的测试题,但感觉题不错,所以还是补一下!

G. [COCI2015-2016#1] UZASTOPNI

感觉这个题的题意相当抽象,不知道是不是翻译的问题 /yun。

首先考虑 dp,一个 naive 的状态涉及是 f ( u , l , r ) f(u,l,r) f(u,l,r) 表示 u u u 子树内是否能选上值域为 [ l , r ] ( v u ∈ [ l , r ] ) [l,r](v_u\in [l,r]) [l,r](vu[l,r]) 的点。

然后发现这个东西相当 shaber,因为 l , r l,r l,r 互不干扰,直接拆状态就行。

f L ( u , x ) fL(u,x) fL(u,x) 表示能否选上 [ x , v u ] [x,v_u] [x,vu] f R ( u , x ) fR(u,x) fR(u,x) 表示能否选上 [ v u , x ] [v_u,x] [vu,x],转移就 bitset 维护一下即可。

时间复杂度 O ( n v ω ) \mathcal O(\frac{nv}{\omega}) O(ωnv)

#include <bits/stdc++.h>
#define pb emplace_back

const int maxn = 1e5 + 5;
const int maxm = 2005;
std::bitset<maxm> L[maxn], R[maxn];
std::vector<int> G[maxn];
int n, a[maxn], vmax;

void dfs(int u, int fa) {
	L[u].set(a[u], 1), R[u].set(a[u], 1);
	for(auto& v : G[u])
		if(v != fa)
			dfs(v, u);
	int x;
	for(x = 0;x < (int)G[u].size();++ x)
		if(a[G[u][x]] >= a[u])
			break ;
	for(int i = x - 1;~ i;-- i) {
		int v = G[u][i];
		if(v == fa)
			continue ;
		if(((R[v] << 1) & L[u]).any())
			L[u] |= L[v];
	}
	for(int i = x;i < (int)G[u].size();++ i) {
		int v = G[u][i];
		if(v == fa)
			continue ;
		if(((R[u] << 1) & L[v]).any())
			R[u] |= R[v];
	}
	return ;
}

int main() {
	scanf("%d", &n);
	for(int i = 1;i <= n;++ i)
		scanf("%d", &a[i]), vmax = std::max(vmax, a[i]);
	for(int i = 1;i < n;++ i) {
		int u, v;
		scanf("%d %d", &u, &v);
		G[u].pb(v);
		G[v].pb(u);
	}
	for(int i = 1;i <= n;++ i)
		std::sort(G[i].begin(), G[i].end(), [&](const int& lhs, const int& rhs) {
			return a[lhs] < a[rhs];
		});
	dfs(1, 0);
	printf("%d\n", L[1].count() * R[1].count());
	return 0;
}

H. [BZOJ 3784] 树上的路径

(由于 bzoj 爆炸了,所以这题现在已经绝版,只能去 hydro 的 bzoj 域交,link

考虑一个 naive 的做法:遇到这类不太好整的 rank 题目,我们考虑二分答案,求出 ≤ m i d \le mid mid 的路径个数,和 m m m 比大小,最小的满足路径个数 ≥ m \ge m m 的就是答案,然后再跑一遍输出即可。这样是 O ( n log ⁡ 2 n log ⁡ V ) \mathcal O(n\log^2n\log V) O(nlog2nlogV),这么不牛。

然后我们来展示一点魔法。前置知识是 [NOI2010] 超级钢琴,我很早之前就写过这题的 题解

然后考虑点分治。固定分治重心为根跑 dfs 序,发现各个子树都是一段连续的区间,然后查询前 m m m 大就是子树间查询,转化到 dfs 序上就是区间查询。

然后这个东西可以拆成:有若干点和区间,查前 m m m 大,和 NOI 那道题一模一样的处理手法。

但是这样是对的吗?实际上没问题。我们点分治的时候一层总共 Θ ( n ) \Theta(n) Θ(n) 个这样的询问,然后分治 O ( log ⁡ n ) \mathcal O(\log n) O(logn) 层,所以询问总数是 O ( n log ⁡ n ) \mathcal O(n\log n) O(nlogn) 级别的。时间复杂度就是高贵的 O ( n log ⁡ 2 n ) \mathcal O(n\log^2n) O(nlog2n)

这道题的最大收获是,加深对超级钢琴这题处理手法的理解,并且知道了点分治配合 dfs 序的处理手法。这么牛。

代码能力真的弱,3k 的代码都写不动谔谔。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值