传送门
题意: 对于一颗有点权的树, 如果i是j的祖先, 那么要满足vi > vj, 问最多可以在这棵树上选择多少个点可以满足这个条件.
思路: 那么这就是树上lis,怎么维护了, 每个点依旧像普通数组这样, 那么就有合并, 要合并某个点和儿子的数字, 然后依旧还是g[i]表示lis长度为i时, 最小的a[i]可以是多少, 那么直接就查lower_bound就行, 又要排序, 和重值, 所以我们就用multiset就可以很好的维护了, 合并时记得启发式合并就行.
AC Code
const int maxn = 2e5+5;
vector<int>g[maxn];
multiset<int>st[maxn];
int a[maxn];
void Un(int x, int y) {
if (sz(st[x]) < sz(st[y])) {
swap(st[x], st[y]);
}
multiset<int>::iterator it = st[y].begin();
for (; it != st[y].end(); it++) {
st[x].insert(*it);
}
}
void dfs(int u) {
for (int i = 0 ; i < sz(g[u]) ; i ++) {
dfs(g[u][i]);
Un(u, g[u][i]);
}
multiset<int>::iterator it = st[u].lower_bound(a[u]);
if (it != st[u].end()) {
st[u].erase(it);
}
st[u].insert(a[u]);
}
void solve() {
int n;
scanf("%d", &n);
for (int i = 1 ; i <= n ; i ++) {
int x;
scanf("%d%d", a+i, &x);
if (x) {
g[x].pb(i);
}
}
dfs(1);
printf("%d\n", sz(st[1]));
}