1. 程式人生 > 其它 >G - Game on Tree 2(對抗搜尋 + 對頂堆維護中位數)

G - Game on Tree 2(對抗搜尋 + 對頂堆維護中位數)

對抗搜尋也叫極大極小值搜尋,其核心思想就是先搜到底部,將葉子節點的值返回上去,之後極大節點選擇所有分支裡的極大值返回,極小節點選擇所有分支裡的極小值返回。

對頂堆維護中位數。emmm其實對頂堆維護中位數是一個板子,不過注意這裡會有奇偶中位數。

注意一下就行了

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int inf = 0x3f3f3f3f; ///1061109567
const int maxn = 1e5+10;


int n, m; int dp[maxn]; int a[maxn]; vector<int> G[maxn]; namespace DDD { multiset<int, less<int> > big; multiset<int, greater<int> > small; //int k; int cnt; ///只求中位數 void init(int kk=1) { small.clear(); big.clear(); //k = kk; cnt = 0
; } void balance() { ///維持上方小根堆比下面大根堆 多k (奇偶會不為k) while (big.size() > small.size() + (cnt%2==0)) { small.insert(*big.begin()); big.erase(big.begin()); } while (small.size() + (cnt%2==0) > big.size()) { big.insert(*small.begin()); small.erase(small.begin()); } }
void _insert(int x) { if (big.size() == 0 || x >= *big.begin()) { big.insert(x); } else { small.insert(x); } balance(); cnt ++; } int get() { // cout << "in small: "; // for (auto i : small ) { // cout << i << " "; // } // cout << endl; // cout << "in big: "; // for (auto i : big) { // cout << i << " "; // } // cout << endl; if (cnt % 2) return *big.begin(); return (*small.begin() + *big.begin()) / 2; } void _delete(int x) { auto p1 = small.find(x); auto p2 = big.find(x); if (p1 != small.end()) { small.erase(p1); balance(); cnt --; } else if (p2 != big.end()) { big.erase(p2); balance(); cnt --; } } }; void DFS(int u, int fa, int d) { // cout << "node: " << u << endl; DDD::_insert(a[u]); int mx = 0, mi = 1e9; for (auto v : G[u]) { if (v == fa) continue; DFS(v, u, d+1); mi = min(dp[v], mi); mx = max(dp[v], mx); } if (mx == 0) { dp[u] = DDD::get(); // cout << u << " " << dp[u] << endl; } else if (d&1) dp[u] = mi; else dp[u] = mx; DDD::_delete(a[u]); } int main() { scanf("%d", &n); 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); G[u].push_back(v); G[v].push_back(u); } DDD::init(); DFS(1, 0, 0); cout << dp[1] << endl; return 0; }