G - Game on Tree 2(主席树+树形dp)
思路:
首先中位数为跟到叶子节点的树链的中位数, 我们能用主席树算出,然后根据中位数来树形dp,深度为奇数则是Alice操作选中位数最大,偶数为BOb操作选中位数最小。
代码
#include <iostream>
#include <vector>
#include <algorithm>
#define mid (l+r>>1)
using namespace std;
const int N=1e5+7;
int n,tot,a[N],rt[N],f[N];
struct node{int lc,rc,v;}tr[40*N];
vector <int> G[N],ho;
int get(int x){return lower_bound(ho.begin(),ho.end(),x)-ho.begin()+1;}
void insert(int &k,int pr,int l,int r,int p){
k=++tot;tr[k]=tr[pr],tr[k].v++;
if(l==r) return;
if(p<=mid) insert(tr[k].lc,tr[pr].lc,l,mid,p);
else insert(tr[k].rc,tr[pr].rc,mid+1,r,p);
}
int ask(int k,int l,int r,int key){
if(l==r) return l;
int tem=tr[tr[k].lc].v;
if(tem>=key) return ask(tr[k].lc,l,mid,key);
else return ask(tr[k].rc,mid+1,r,key-tem);
}
void dfs(int p,int fa,int dep){
insert(rt[p],rt[fa],1,n,get(a[p]));
int ok=1;
if(dep&1) f[p]=0;
else f[p]=1e9;
for(auto v:G[p]){
if(v==fa) continue;
dfs(v,p,dep+1);
ok=0;
if(dep&1){
f[p]=max(f[p],f[v]);
}else{
f[p]=min(f[p],f[v]);
}
}
if(ok){
if(dep&1){
f[p]=ho[ask(rt[p],1,n,(dep+1)/2)-1];
}else{
f[p]=(ho[ask(rt[p],1,n,(dep+1)/2)-1]+ho[ask(rt[p],1,n,(dep+1)/2+1)-1])/2;
}
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
ho.push_back(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);
}
ho.erase(unique(ho.begin(),ho.end()),ho.end());
sort(ho.begin(),ho.end());
dfs(1,0,1);
printf("%d\n",f[1]);
}