VJ地址
题意:给一个有根树给你,计算一下满足下列条件的序列对的数目
(1)u是v的祖先(不能是它自己)
(2)a[v]*a[u]<=k
思路:用DFS序分裂每一条链,使链上的点都是当前加入点的祖先,用树状数组维护,or线段树,因为是单点修改就用就树状数组了。 每次加入点前,计算小于等于k/a[v]点的数量。还有数据大小是1e9,但是只有1e5个点,要离散化处理。
ps:还有要自己找到根节点。
具体细节:
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <bits/stdc++.h>
#define INF 2e18
#define inf 0x3f3f3f3f
#define FILL(a,b) (memset(a,b,sizeof(a)))
#define re register
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(a) ((a)&-(a))
#define ios std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
#define fi first
#define se secondusing namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int > pii;
int dx[4]= {-1,1,0,0},dy[4]= {0,0,1,-1};
const ll mod=1e9+7;
const ll N =2e5+10;
const double eps = 1e-4;
const double pi=acos(-1);
ll gcd(int a,int b){return !b?a:gcd(b,a%b);}
using namespace std;
vector<int> g[N];
ll n,k;
ll a[N];
ll lsh[N];
ll sum;
ll cnt;
ll c[N];
int vis[N];
ll getid(ll x)
{return lower_bound(lsh+1,lsh+cnt+1,x)-lsh;
}
void add(ll x,ll v)
{while(x<=N){c[x]+=v;x+=lowbit(x);}
}
ll query(ll x)
{ll ans=0;while(x){ans+=c[x];x-=lowbit(x);}return ans;
}
void dfs(int u,int p){add(getid(a[u]),1);for(int v:g[u]){if(v==p) continue;sum+=query(getid(k/a[v]+1)-1);dfs(v,u);}add(getid(a[u]),-1);
}
void sovle(){sum=0;cin>>n>>k;FILL(c,0);FILL(vis,0);for(int i=1;i<=n;i++) {cin>>a[i];lsh[i]=a[i];}sort(lsh+1,lsh+1+n);cnt=unique(lsh+1,lsh+n+1)-lsh-1;for(int i=1;i<n;i++){int u,v;cin>>u>>v;g[u].push_back(v);g[v].push_back(u);vis[v]=1;}for(int i=1;i<=n;i++){if(!vis[i]) {dfs(i,0);break;}}cout<<sum<<endl;for(int i=1;i<=n;i++) g[i].clear();
}
int main()
{iosint t=1;cin>>t;while(t--){sovle();}return 0;
}