ABC218G
我们假定 \(1\) 为根,那么我们只能往叶子节点走。
于是我们可以树上 DP。
我们记录 \(f_{u}\) 表示 \(u\) 这棵子树可能的答案。
-
当 \(dep_u\) 为奇数时,此时必定是 Taro 操作,所以应该取子树的最大 \(f_{v}\)。
-
否则,就是 Jiro 操作,所以应该取子树的最小 \(f_{v}\)。
在叶子节点时,要求当前的中位数。
我们用线段树维护,时间复杂度是 \(O(nlogn)\) 的。
这样就可以了。
My Code
#include<bits/stdc++.h>
using namespace std;
inline int read() {
int s=1,a=0;
char c=getchar();
while(!isdigit(c)) {
if(c=='-') s=-s;
c=getchar();
}
while(isdigit(c)) {
a=a*10+c-'0';
c=getchar();
}
return s*a;
}
const int N=2e5+8;
#define ls p<<1
#define rs p<<1|1
int n,val[N];
int f[N],node[N],cnt;
struct sgt {
int siz[N<<2];
void update(int p) {
siz[p]=siz[ls]+siz[rs];
}
void build(int l,int r,int p) {
if(l==r) {
siz[p]=0;
return;
}
int mid=(l+r)>>1;
build(l,mid,ls);
build(mid+1,r,rs);
update(p);
}
void change(int l,int r,int p,int x,int f) {
if(l==r) {
siz[p]+=f;
return;
}
int mid=(l+r)>>1;
if(x<=mid) change(l,mid,ls,x,f);
else change(mid+1,r,rs,x,f);
update(p);
}
int query(int l,int r,int p,int k) {
if(l==r) {
return l;
}
int mid=(l+r)>>1;
if(siz[ls]>=k) return query(l,mid,ls,k);
else return query(mid+1,r,rs,k-siz[ls]);
}
} wgj;
int getmid() {
if(wgj.siz[1]&1) {
return node[wgj.query(1,cnt,1,(wgj.siz[1]+1)/2)];
}
else {
int d1=wgj.query(1,cnt,1,wgj.siz[1]/2),d2=wgj.query(1,cnt,1,wgj.siz[1]/2+1);
// cout<<d1<<" "<<d2<<endl;
return (node[d1]+node[d2])/2;
}
}
vector <int> G[N];
void dfs(int u,int fa,int dep) {
wgj.change(1,cnt,1,val[u],1);
int mx=-1,mn=0x7f7f7f7f;
for(auto v:G[u]) {
if(v==fa) continue;
dfs(v,u,dep+1);
// cout<<v<<" "<<f[v]<<endl;
mn=min(mn,f[v]),mx=max(mx,f[v]);
}
if(mx==-1) /*cout<<u<<" ",*/f[u]=getmid();
else if(dep&1) f[u]=mx;
else f[u]=mn;
wgj.change(1,cnt,1,val[u],-1);
}
signed main() {
n=read();
for(int i=1; i<=n; i++) {
val[i]=read();
node[i]=val[i];
}
sort(node+1,node+n+1);
cnt=unique(node+1,node+n+1)-node-1;
for(int i=1; i<=n; i++) {
val[i]=lower_bound(node+1,node+cnt+1,val[i])-node;
}
wgj.build(1,cnt,1);
for(int i=1; i<n; i++) {
int u=read(),v=read();
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,0,1);
printf("%d\n",f[1]);
return 0;
}