可以使用map实现的树上启发式合并解决。关于信息,对于每个节点 ,往上传小于
的信息和
的信息。关于计算答案,在合并时统计该点作为权值小于
的点的路径部分和该点作为路径始发点。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
const int mod=998244353;
const int N=2e5+10;
int n,head[N],nxt[N<<1],to[N<<1],cnt,val[N],siz[N],ans;
vector<map<int,int,greater<int> > >vr;
void add(int u,int v){
to[++cnt]=v;
nxt[cnt]=head[u];
head[u]=cnt;
}
void dfs(int u,int fa){
siz[u]=1;
int zz=0,dz=0;
for(int i=head[u];i!=-1;i=nxt[i]){
int v=to[i];
if(v!=fa){
dfs(v,u);
siz[u]+=siz[v];
if(siz[v]>dz){
zz=v;
dz=siz[v];
}
}
}
if(zz){
swap(vr[u],vr[zz]);
int sum=0;
set<int>st;
for(int i=head[u];i!=-1;i=nxt[i]){
int v=to[i];
if(v!=fa&&v!=zz){
for(pii x:vr[v]){
vr[u][x.first]+=x.second;
if(x.first<val[u])ans+=(vr[u][x.first]-x.second)*x.second;
}
vr[v].clear();
}
}
for(pii p:vr[u]){
if(p.first<val[u])break;
if(p.first==val[u])ans+=p.second;
st.insert(p.first);
}
for(int x:st)vr[u].erase(x);
}
vr[u][val[u]]=1;
}
void solve(){
cin>>n;
cnt=ans=0;
for(int i=1;i<=n;i++)head[i]=-1;
vr=vector<map<int,int,greater<int> > >(n+1,map<int,int,greater<int> >{});
for(int i=1;i<=n;i++)cin>>val[i];
for(int i=1;i<n;i++){
int a,b;cin>>a>>b;
add(a,b);
add(b,a);
}
dfs(1,0);
cout<<ans*2<<"\n";
}
signed main(){
ios::sync_with_stdio(0);cout.tie(0);cin.tie(0);
solve();
}

京公网安备 11010502036488号