给定一棵树,求其所有联通块的权值第k大的和
树形DP统计\(f[u][i]\),表示\(u\)作为第\(i\)大的方案数 , 答案就是\(\sum f[u][K]\)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define Debug(x) cout<<#x<<"="<<x<<endl
using namespace std;
typedef long long LL;
const int INF=1e9+7;
inline LL read(){
register LL x=0,f=1;register char c=getchar();
while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
return f*x;
}
const int N=1705;
const int M=3405;
const int mod=64123;
struct Edge{
int v,w,nxt;
}e[M];
int first[N],Ecnt=0;
inline void Add_edge(int u,int v,int w=0){
e[++Ecnt]=(Edge){v,w,first[u]};
first[u]=Ecnt;
}
int f[N][N],size[N],tmp[N],a[N],b[N];
int n,K,W,ans;
inline int add(int x,int y){x+=y;return x>mod?x-mod:x;}
inline int mul(LL x,int y){x*=y;return x>mod?x%mod:x;}
inline void dfs(int u,int pre){
f[u][b[u]]=1,size[u]=b[u];//第0大:无影响
for(int i=first[u];i;i=e[i].nxt){
int v=e[i].v;
if(v==pre) continue;
dfs(v,u);
for(int j=0;j<=size[u]&&j<=K;j++){
for(int k=0;k<=size[v]&&k<=K;k++)
tmp[j+k]=add(tmp[j+k],mul(f[u][j],f[v][k]));
}
size[u]+=size[v];
for(int j=0;j<=size[u];j++){
f[u][j]=add(f[u][j],tmp[j]);
tmp[j]=0;
}
}
}
int main(){
n=read(),K=read(),W=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n-1;i++){
int x=read(),y=read();
Add_edge(x,y);
Add_edge(y,x);
}
for(int i=1;i<=n;i++){
int sum=0;
for(int j=1;j<=n;j++){
if(a[j]>a[i]||(a[j]==a[i]&&j>=i)) b[j]=1,sum++;//只算权值>=它的
else b[j]=0;
}
if(sum<K) continue;
memset(f,0,sizeof f);
dfs(i,0);
ans=add(ans,mul(a[i],f[i][K]));//i点作为第K大算贡献
}
printf("%d\n",ans);
}