今天不是我们的题啊,是提高组的测试题,但感觉题不错,所以还是补一下!
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 的代码都写不动谔谔。