multiset 启发式合并贪心维护 LIS 的做法就不多说了,网上题解一大堆,着重讲一下线段树合并维护 \(dp\)。

\(O(n^2)\) 的 \(dp\) 非常显然。离散化后,设 \(dp[u][i]\) 表示节点 \(u\) 的子树中,最大值为 \(i\) 时最多取多少个节点。转移时考虑是否将节点 \(u\) 加入大根堆并分类讨论。

这样的状态不支持快速合并。考虑优化状态,设 \(dp[u][i]\) 表示节点 \(u\) 的子树中,最大值 \(\le i\) 时最多取多少个节点,并尝试使用线段树合并来维护。

转移同样考虑两种情况。如果 \(u\) 不取,那么直接 \(dp[u][i] = \sum dp[v][i]\) 即可,将 \(u\) 的儿子的线段树合并。合并之后,如果 \(u\) 取,就要求子树中取的最大值都 \(\lt val[u]\),那么要用 \(\max\limits_{i \lt val[u]}dp[u][i]+1\) 去更新 \(dp[u][\ge val[u]]\)。

注意到,根据状态的设计,\(dp[u]\) 其实是一个单调不减的序列,所以 \(\max\limits_{i \lt val[u]} dp[u][i]+1\) 其实相当于 \(dp[u][val[u]-1]+1\)。同时由于 \(dp[u]\) 单调不减,所以 \(dp[u][\ge val[u]]\) 中会被更新的值是一段左端点为 \(val[u]\) 的区间,这段区间的值都是 \(dp[u][val[u]-1]\)。

于是,可以二分出区间的右端点。具体地,二分找到最后一个 \(i\) 使得 \(dp[u][i] \lt dp[u][val[u]-1]+1\),然后在线段树上将区间 \([val[u],i]\) 覆盖或直接 \(+1\) 即可,需要标记永久化。

综上所述,该算法的时间复杂度为 \(O(n \log^2 n)\)。

/**
* @file: BZOJ4919.cpp
* @author: yaoxi-std
* @url:
*/
#pragma GCC optimize ("O2")
#pragma GCC optimize ("Ofast", "inline", "-ffast-math")
#pragma GCC target ("avx,sse2,sse3,sse4,mmx")
#include <bits/stdc++.h>
using namespace std;
#define resetIO(x) \
freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout)
#define debug(fmt, ...) \
fprintf(stderr, "[%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
template <class _Tp>
inline _Tp& read(_Tp& x) {
bool sign = false; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) sign |= (ch == '-');
for (x = 0; isdigit(ch); ch = getchar()) x = x * 10 + (ch ^ 48);
return sign ? (x = -x) : x;
}
template <class _Tp>
inline void write(_Tp x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) write(x / 10);
putchar((x % 10) ^ 48);
}
bool m_be;
using ll = long long;
const int MAXN = 2e5 + 10;
const int INF = 0x3f3f3f3f;
int n, m, a[MAXN], fa[MAXN], val[MAXN];
vector<int> g[MAXN];
struct SegmentTree {
struct Node {
int ls, rs, sum;
} nd[MAXN * 25];
int tot, rt[MAXN];
int& operator[](int i) { return rt[i]; }
void update(int& i, int l, int r, int ql, int qr, int v) {
if (ql > qr) return;
if (!i) i = ++tot;
if (ql <= l && r <= qr) return void(nd[i].sum += v);
int mid = (l + r) >> 1;
if (ql <= mid) update(nd[i].ls, l, mid, ql, qr, v);
if (qr > mid) update(nd[i].rs, mid + 1, r, ql, qr, v);
}
int query(int i, int l, int r, int p) {
if (!i || !p) return 0;
if (l == r) return nd[i].sum;
int mid = (l + r) >> 1;
if (p <= mid) return nd[i].sum + query(nd[i].ls, l, mid, p);
return nd[i].sum + query(nd[i].rs, mid + 1, r, p);
}
void merge(int& x, int y, int l, int r) {
if (!x || !y) return void(x = x | y);
if (l == r) return void(nd[x].sum += nd[y].sum);
int mid = (l + r) >> 1;
merge(nd[x].ls, nd[y].ls, l, mid);
merge(nd[x].rs, nd[y].rs, mid + 1, r);
nd[x].sum += nd[y].sum;
}
} sgt;
void dfs(int u) {
for (auto v : g[u]) dfs(v), sgt.merge(sgt[u], sgt[v], 1, m);
int tmp = sgt.query(sgt[u], 1, m, a[u] - 1) + 1;
int l = a[u], r = m, pos = a[u] - 1;
while (l <= r) {
int mid = (l + r) >> 1;
if (sgt.query(sgt[u], 1, m, mid) < tmp)
l = mid + 1, pos = mid;
else
r = mid - 1;
}
sgt.update(sgt[u], 1, m, a[u], pos, 1);
}
bool m_ed;
signed main() {
read(n);
for (int i = 1; i <= n; ++i)
read(a[i]), read(fa[i]), val[i] = a[i], g[fa[i]].push_back(i);
sort(val + 1, val + n + 1), m = unique(val + 1, val + n + 1) - val - 1;
for (int i = 1; i <= n; ++i) a[i] = lower_bound(val + 1, val + m + 1, a[i]) - val;
dfs(1), write(sgt.query(1, 1, m, m)), putchar('\n');
return 0;
}

BZOJ4919 大根堆(树形dp+线段树合并)的更多相关文章

  1. 【洛谷5298】[PKUWC2018] Minimax(树形DP+线段树合并)

    点此看题面 大致题意: 有一棵树,给出每个叶节点的点权(互不相同),非叶节点\(x\)至多有两个子节点,且其点权有\(p_x\)的概率是子节点点权较大值,有\(1-p_x\)的概率是子节点点权较小值. ...

  2. BZOJ4919 大根堆(动态规划+treap+启发式合并)

    一个显然的dp是设f[i][j]为i子树内权值<=j时的答案,则f[i][j]=Σf[son][j],f[i][a[i]]++,f[i][a[i]+1~n]对其取max.这样是可以线段树合并的, ...

  3. 【pkuwc2018】 【loj2537】 Minmax DP+线段树合并

    今年年初的时候参加了PKUWC,结果当时这一题想了快$2h$都没有想出来.... 哇我太菜啦.... 昨天突然去搜了下哪里有题,发现$loj$上有于是就去做了下. 结果第一题我5分钟就把所有细节都想好 ...

  4. [BZOJ5461][LOJ#2537[PKUWC2018]Minimax(概率DP+线段树合并)

    还是没有弄清楚线段树合并的时间复杂度是怎么保证的,就当是$O(m\log n)$吧. 这题有一个显然的DP,dp[i][j]表示节点i的值为j的概率,转移时维护前缀后缀和,将4项加起来就好了. 这个感 ...

  5. BZOJ.5461.[PKUWC2018]Minimax(DP 线段树合并)

    BZOJ LOJ 令\(f[i][j]\)表示以\(i\)为根的子树,权值\(j\)作为根节点的概率. 设\(i\)的两棵子树分别为\(x,y\),记\(p_a\)表示\(f[x][a]\),\(p_ ...

  6. LOJ2537. 「PKUWC2018」Minimax【概率DP+线段树合并】

    LINK 思路 首先暴力\(n^2\)是很好想的,就是把当前节点概率按照权值大小做前缀和和后缀和然后对于每一个值直接在另一个子树里面算出贡献和就可以了,注意乘上选最大的概率是小于当前权值的部分,选最小 ...

  7. [PKUWC2018]Minimax [dp,线段树合并]

    好妙的一个题- 我们设 \(f_{i,j}\) 为 \(i\) 节点出现 \(j\) 的概率 设 \(l = ch[i][0] , r = ch[i][1]\) 即左儿子右儿子 设 \(m\) 为叶子 ...

  8. P6847-[CEOI2019]Magic Tree【dp,线段树合并】

    正题 题目链接:https://www.luogu.com.cn/problem/P6847 题目大意 \(n\)个点的一棵树上,每个时刻可以割掉一些边,一些节点上有果实表示如果在\(d_i\)时刻这 ...

  9. POJ 3162 Walking Race 树形DP+线段树

    给出一棵树,编号为1~n,给出数m 漂亮mm连续n天锻炼身体,每天会以节点i为起点,走到离i最远距离的节点 走了n天之后,mm想到知道自己这n天的锻炼效果 于是mm把这n天每一天走的距离记录在一起,成 ...

随机推荐

  1. C语言中的位域的使用

    转载:http://blog.sina.com.cn/s/blog_648d306d0100mv1c.html C语言中的位域的使用一.位域 有些信息在存储时,并不需要占用一个完整的字节, 而只需占几 ...

  2. MyBatis(介绍和环境配置)

    ORM(Object Relational Mapping)  设计模式,思想 对象关系映射,是一种数据持久化技术.它在对象模型和关系型数据库之间建立起对应关系,并且提供了一种机制,通过JavaBea ...

  3. BigDecimal的运算——加减乘除

    BigDecimal的运算--加减乘除 1.初始化(尽量用字符串的形式初始化) BigDecimal num12 = new BigDecimal("0.005"); BigDec ...

  4. 2021 CCPC 威海站 VP记录(题解)

    2021 CCPC 威海站 VP记录(题解) 题目顺序为vp时开题顺序: A - Goodbye, Ziyin! 签到,连边数小于等于2的可以作为二叉树根,若有大于4的直接输出0. code: voi ...

  5. ubuntu+Django + nginx + uwsgi 部署

    ubuntu+Django + nginx + uwsgi 部署 0.前期准备 注意:以下几件事都必须在激活虚拟环境下完成 运行以下命令生成项目所需的依赖列表,会在项目根目录生成一个requireme ...

  6. .net 温故知新:【9】.NET日志记录 ILogger使用和原理

    日志 日志作为我们程序记录的"黑匣子"是不论什么系统都会使用到的,比如我们经常使用的log4net就是第三方日志记录提供程序.NET 支持使用各种内置和第三方日志记录提供程序的日志 ...

  7. Java:String、StringBuilder、StringJoiner学习笔记

    String创建的俩种方式 1.直接赋值 String str = "Hello World!"; 当使用直接赋值的方式去创建字符串的时候,虚拟机会去串池里去检查字符串是否存在,如 ...

  8. Go语言核心36讲24

    你好,我是郝林,今天我们继续来聊聊panic函数.recover函数以及defer语句的内容. 我在前一篇文章提到过这样一个说法,panic之中可以包含一个值,用于简要解释引发此panic的原因. 如 ...

  9. toB应用私有化交付发展历程、技术对比和选型

    由于数据隐私和网络安全的考虑,大多数toB场景的客户需要私有化应用交付,也就是需要交付到客户的环境里,这样的客户有政府.金融.军工.公安.大型企业.特色行业等,这些私有化场景限制很多,如何提高私有化应 ...

  10. i春秋wanna to see your hat?

    打开题目网页发现是个选择帽子的网页,点击超链接进入一个网页让我们输入我们的name然后匹配帽子颜色(其实不管怎么填都是绿色的)这里也有个注册窗口 先查看源码没什么特别发现,再试试抓包吧 在这个界面抓包 ...