#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const ll N=1e3+5;
string s; // 存储每个节点的二进制位(0/1)
vector<vector<ll>>adj(N); // 树的双向邻接表
ll n,l,r; // n:节点数;l/r:二进制值的范围上下限
ll cnt=0; // 统计符合条件的路径数量
unordered_map<ll,bool>m; // 标记节点是否已访问(防DFS回退、走重复节点)
// DFS核心函数:遍历以x为当前节点的路径,sum为当前路径的二进制值
// 算法步骤:1.遍历当前节点的所有邻接节点 2.防回退 3.计算新路径的二进制值 4.判断是否在范围 5.剪枝 6.递归遍历下一个节点 7.回溯恢复标记
void dfs(ll x,ll sum){
// 步骤1:遍历当前节点x的所有邻接节点t
for(auto t:adj[x]){
// 步骤2:防回退(跳过已访问的节点,避免走回头路形成环)
if(m[t]!=false)continue;
// 步骤3:计算新增节点t后的路径二进制值(左移1位 += 当前节点t的二进制值)
ll n_sum=sum<<1; // 二进制左移1位 = 数值×2
if(s[t-1]-'0'==1){ // 节点t的二进制位是1,加到新值中
n_sum+=1;
}
// 步骤4:判断新路径值是否在[l,r]范围内,符合则计数+1
if(n_sum>=l&&n_sum<=r){
cnt++;
}
// 步骤5:剪枝优化:若新值已超过r,后续路径只会更大,直接跳过该分支
else if(n_sum>r){
continue;
}
// 步骤6:标记节点t为已访问,递归遍历以t为当前节点的后续路径
m[t]=true;
dfs(t,n_sum);
// 步骤7:回溯:恢复节点t的未访问状态,供其他分支遍历
m[t]=false;
}
}
int main(){
ios::sync_with_stdio(0),cin.tie(0); // 加速cin/cout输入输出
cin>>n>>l>>r; // 输入节点数、范围上下限
cin>>s; // 输入每个节点的二进制位(s[0]对应节点1,s[1]对应节点2...)
// 步骤1:构建树的双向邻接表(树是无向图,需双向存储边)
for(ll i=1;i<=n-1;i++){
ll u,v;
cin>>u>>v;
adj[u].emplace_back(v);
adj[v].emplace_back(u);
m[u]=false; // 初始化节点访问标记为未访问
m[v]=false;
}
// 边界处理:只有1个节点时无路径,直接输出0
if(n==1){
cout<<0;
return 0;
}
// 步骤2:枚举每个节点作为路径的起点
for(ll i=1;i<=n;i++){
m[i]=true; // 标记起点为已访问(避免路径包含自身)
// 调用DFS:起点为i,初始路径值为节点i的二进制位
dfs(i,s[i-1]-'0');
m[i]=false; // 回溯:恢复起点的未访问状态
}
// 步骤3:输出符合条件的路径总数
cout<<cnt;
return 0;
}