题意:
给你一棵树,每个节点上都有一个权值。
让你找到一个连通的节点集合,使得根据节点权值升序排序后,第i个节点到第i+1个节点所经过的其它节点权值都小于第i个节点的权值。
问你这样的集合最大的size。
思路:
比较朴素的思路:枚举以每个节点作为根,进行dfs搜寻所有比父亲节点权值大的节点个数,复杂度n^2。如果我们开一个数组保存之前已经统计过的节点个数,则复杂度降为O(n)。
赛中我们队是dfs开栈交c++过的,但实际这并非正解。
后来问过出题人,杭电的栈虽小,但若可以使用开栈代码,则内存有多大就可以开多大。50万正常来说是承受不了的,普通正常赛事中栈深大概就26万。
正解:拓扑排序。根据输入建边,权值大的指向权值小的。
code1(拓扑排序、正解):
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5+5;
typedef long long LL;
int n;
int w[N];
int cnt[N];
int ind[N];
vector <int> edge[N];
void solve() {
fill(cnt+1, cnt+n+1, 1);
queue <int> q;
for(int i = 1;i <= n; i++)
if(ind[i] == 0) q.push(i);
while(!q.empty()) {
int u = q.front(); q.pop();
for(auto &v:edge[u]) {
//if(w[i] < w[u]) continue;
cnt[v] += cnt[u];
if(--ind[v] == 0) q.push(v);
}
}
int res = 0;
for(int i = 1;i <= n; i++) res = max(res, cnt[i]);
printf("%d\n", res);
}
int main() {
while(scanf("%d", &n) != EOF) {
fill(edge+1, edge+n+1, vector <int>());
fill(ind+1, ind+n+1, 0);
for(int i = 1;i <= n; i++) scanf("%d", &w[i]);
for(int i = 1;i <= n-1; i++) {
int u, v;
scanf("%d%d", &u, &v);
if(w[u] < w[v]) swap(u, v);
edge[u].push_back(v);
ind[v]++;
}
solve();
}
return 0;
}
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <vector>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int N = 5e5+5;
typedef long long LL;
int n;
int a[N];
int cnt[N];
bool vis[N];
vector <int> edge[N];
int dfs(int u, int p) {
int ret = 0;
vis[u] = true;
for(auto &v : edge[u]) {
if(v == p) continue;
if(a[v] < a[u]) continue;
if(vis[v]) ret += cnt[v];
else ret += dfs(v, u);
}
cnt[u] = ret+1;
return ret+1;
}
void solve() {
int res = 0;
for(int i = 1;i <= n; i++){
if(vis[i]) res = max(res, cnt[i]);
else res = max(res, dfs(i, -1));
}
printf("%d\n", res);
}
int main() {
while(scanf("%d", &n) != EOF) {
for(int i = 1;i <= n; i++){
edge[i].clear();
vis[i] = false;
cnt[i] = 0;
}
for(int i = 1;i <= n; i++) scanf("%d", &a[i]);
for(int i = 1;i <= n-1; i++) {
int u, v;
scanf("%d%d", &u, &v);
edge[u].push_back(v);
edge[v].push_back(u);
}
solve();
}
return 0;
}