题意
给定一颗树,求节点 1 1 1到各个节点路径上的最长上升子序列的长度
分析
之前只知道对序列进行二分
n
l
o
g
n
nlogn
nlogn的做法
给定一个数组1 4 3 6 2 5 8 7 8 9
当前数 | ||||||
---|---|---|---|---|---|---|
1 | 1 | |||||
4 | 1 | 4 | ||||
3 | 1 | 3 | ||||
6 | 1 | 3 | 6 | |||
2 | 1 | 2 | 6 | |||
5 | 1 | 2 | 5 | |||
8 | 1 | 2 | 5 | 8 | ||
7 | 1 | 2 | 5 | 7 | ||
8 | 1 | 2 | 5 | 7 | 8 | |
9 | 1 | 2 | 5 | 7 | 8 | 9 |
每次都是求,①数组中有多少个小于当前数,也可以说是求②当前数能够放到的位置,此时这个位置大小就是当前数为结尾的 L I S LIS LIS长度大小
对于①来说,在数组中进行二分查找即可
对于②来说,得知道比当前数略小的数的最大位置
所以这里应运而生两种做法
①维护一个一般数组,将当前数放到小于自己的最后一个数的后一个位置,当前位置大小为以此数结尾的
L
I
S
LIS
LIS长度
②维护一个权值数组(桶),每次找到当前数值为下标位置的左边所有数的最大值,因此可以用权值线段树维护
由 L I S LIS LIS的两种做法,都可以得到这题的解法,唯一需要注意的就是对于数值的还原,两个子树的链是互不影响的
代码(一般数组二分)183ms
//abc165_f
/*
@Author: YooQ
*/
#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
#define ll long long
#define int long long
#define FILE_OUT freopen("out", "w", stdout);
#define FILE_IN freopen("in", "r", stdin);
#define debug(x) cout << #x << ": " << x << "\n";
#define max3(a, b, c) max(a, max(b, c))
#define min3(a, b, c) min(a, min(b, c))
#define MAX(a, b) (a >= b ? a : a = b)
#define MIN(a, b) (a <= b ? a : a = b)
#define AC 0
#define WA 1
#define INF 0x3f3f3f3f
const ll MAX_N = 1e6+5;
const ll MOD = 1e9+7;
int N, M, K;
int head[MAX_N];
int nxt[MAX_N];
int tot = 0;
struct Edge {
int to, nxt;
}edge[MAX_N<<1];
void addEdge(int u, int v) {
edge[tot].nxt = head[u];
edge[tot].to = v;
head[u] = tot++;
edge[tot].nxt = head[v];
edge[tot].to = u;
head[v] = tot++;
}
int arr[MAX_N];
int ans[MAX_N];
int brr[MAX_N];
void dfs2(int u, int from) {
int x = lower_bound(brr+1, brr+1+N, arr[u]) - brr;
int _x = brr[x];
brr[x] = arr[u];
ans[u] = max(ans[from], x);
for (int i = head[u], v; ~i; i = edge[i].nxt) {
if ((v = edge[i].to) == from) continue;
dfs2(v, u);
}
brr[x] = _x;
}
void init() {
memset(head, -1, sizeof head);
fill(brr+1, brr+MAX_N, MOD);
tot = 0;
}
void solve() {
init();
cin >> N;
for (int i = 1; i <= N; ++i) {
cin >> arr[i];
}
for (int i = 1, u, v; i < N; ++i) {
cin >> u >> v;
addEdge(u, v);
}
dfs2(1, 1);
for (int i = 1; i <= N; ++i) {
cout << ans[i] << "\n";
}
}
signed main() {
#ifndef ONLINE_JUDGE
// FILE_IN
FILE_OUT
#endif
int T = 1;//cin >> T;
while (T--) solve();
return AC;
}
代码(权值线段树)341ms
//abc165_f
/*
@Author: YooQ
*/
#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
#define ll long long
#define int long long
#define FILE_OUT freopen("out", "w", stdout);
#define FILE_IN freopen("in", "r", stdin);
#define debug(x) cout << #x << ": " << x << "\n";
#define max3(a, b, c) max(a, max(b, c))
#define min3(a, b, c) min(a, min(b, c))
#define MAX(a, b) (a >= b ? a : a = b)
#define MIN(a, b) (a <= b ? a : a = b)
#define AC 0
#define WA 1
#define INF 0x3f3f3f3f
const ll MAX_N = 1e6+5;
const ll MOD = 1e9+7;
int N, M, K;
int head[MAX_N];
int nxt[MAX_N];
int tot = 0;
struct Edge {
int to, nxt;
}edge[MAX_N<<1];
void addEdge(int u, int v) {
edge[tot].nxt = head[u];
edge[tot].to = v;
head[u] = tot++;
edge[tot].nxt = head[v];
edge[tot].to = u;
head[v] = tot++;
}
int tr[MAX_N];
void push_up(int rt) {
tr[rt] = max(tr[rt<<1], tr[rt<<1|1]);
}
void update(int rt, int l, int r, int x, int k) {
if (l == r) {
tr[rt] = k;
return;
}
int mid = l + ((r-l)>>1);
if (x <= mid) update(rt<<1, l, mid, x, k);
else update(rt<<1|1, mid + 1, r, x, k);
push_up(rt);
}
int query(int rt, int l, int r, int x, int y) {
if (y < x) return 0;
if (x <= l && r <= y) {
return tr[rt];
}
int mid = l + ((r-l)>>1);
if (y <= mid) return query(rt<<1, l, mid, x, y);
else if (x > mid) return query(rt<<1|1, mid+1, r, x, y);
else return max(query(rt<<1, l, mid, x, y), query(rt<<1|1, mid+1, r, x, y));
}
int arr[MAX_N];
int ans[MAX_N];
int uniarr[MAX_N];
int unicnt = 0;
void dfs(int u, int from) {
int x = query(1, 1, unicnt, arr[u], arr[u]);
int y = max(x, query(1, 1, unicnt, 1, arr[u]-1) + 1);
ans[u] = max(ans[from], y);
update(1, 1, unicnt, arr[u], y);
for (int i = head[u], v; ~i; i = edge[i].nxt) {
if ((v = edge[i].to) == from) continue;
dfs(v, u);
}
update(1, 1, unicnt, arr[u], x);
}
void init() {
memset(head, -1, sizeof head);
tot = 0;
}
void solve() {
init();
cin >> N;
unicnt = 0;
for (int i = 1; i <= N; ++i) {
cin >> arr[i];
uniarr[++unicnt] = arr[i];
}
for (int i = 1, u, v; i < N; ++i) {
cin >> u >> v;
addEdge(u, v);
}
sort(uniarr+1, uniarr+1+unicnt);
unicnt = unique(uniarr+1, uniarr+1+unicnt) - uniarr - 1;
for (int i = 1; i <= N; ++i) {
arr[i] = lower_bound(uniarr+1, uniarr+1+unicnt, arr[i]) - uniarr;
}
dfs(1, 1);
for (int i = 1; i <= N; ++i) {
cout << ans[i] << "\n";
}
}
signed main() {
#ifndef ONLINE_JUDGE
// FILE_IN
FILE_OUT
#endif
int T = 1;//cin >> T;
while (T--) solve();
return AC;
}