Problem Description
You are given a rooted tree
of N nodes,
labeled from 1 to N.
To the ith
node a non-negative value ai is
assigned.An ordered pair
of nodes (u,v) is
said to be weak if
(1) u is an ancestor of v (Note: In this problem a node u is not considered an ancestor of itself);
(2) au×av≤k.
Can you find the number of weak pairs in the tree?
(1) u is an ancestor of v (Note: In this problem a node u is not considered an ancestor of itself);
(2) au×av≤k.
Can you find the number of weak pairs in the tree?
Input
There are multiple cases in the data set.
The first line of input contains an integer T denoting number of test cases.
For each case, the first line contains two space-separated integers, N and k, respectively.
The second line contains N space-separated integers, denoting a1 to aN.
Each of the subsequent lines contains two space-separated integers defining an edge connecting nodes u and v , where node u is the parent of node v.
Constrains:
1≤N≤105
0≤ai≤109
0≤k≤1018
The first line of input contains an integer T denoting number of test cases.
For each case, the first line contains two space-separated integers, N and k, respectively.
The second line contains N space-separated integers, denoting a1 to aN.
Each of the subsequent lines contains two space-separated integers defining an edge connecting nodes u and v , where node u is the parent of node v.
Constrains:
1≤N≤105
0≤ai≤109
0≤k≤1018
Output
For each test case, print a single integer on a single line denoting the number of weak pairs in the tree.
Sample Input
1 2 3 1 2 1 2
Sample Output
1一道数据结构好题,从不同的角度有不同的做法,树上直接做可以自上向下统计每个点对于祖先的贡献,用平衡树或动态线段树可以搞定,离散后可以树状数组或线段树。自下向上可以用线段树或平衡树的启发式合并,还可以树形转线形,询问区间里小于某个值的数有几个,可以线段树加二分,或者可持久化线段树等等。这里我用了最近学会的线段树启发式合并自下向上用拓扑排序搞定。#include<set> #include<map> #include<ctime> #include<cmath> #include<stack> #include<queue> #include<bitset> #include<cstdio> #include<string> #include<cstring> #include<iostream> #include<algorithm> #include<functional> #define rep(i,j,k) for (int i = j; i <= k; i++) #define per(i,j,k) for (int i = j; i >= k; i--) #define loop(i,j,k) for (int i = j;i != -1; i = k[i]) #define lson x << 1, l, mid #define rson x << 1 | 1, mid + 1, r #define ff first #define ss second #define mp(i,j) make_pair(i,j) #define pb push_back #define pii pair<int,LL> #define in(x) scanf("%d", &x); using namespace std; typedef long long LL; const int low(int x) { return x&-x; } const double eps = 1e-4; const int INF = 0x7FFFFFFF; const int mod = 998244353; const int N = 1e5 + 10; int T, n, x, y, l, r; LL m; int fa[N], cnt[N], a[N]; int f[35 * N], L[35 * N], R[35 * N], g[N], tot; int node() { L[tot] = R[tot] = f[tot] = 0; return tot++; } void make(int &x, int l, int r, int u) { if (!x) x = node(); f[x] = 1; if (l == r) return; int mid = l + r >> 1; if (u <= mid) make(L[x], l, mid, u); else make(R[x], mid + 1, r, u); } int find(int x, int l, int r, LL u) { if (!x || u < l) return 0; if (l == r) return f[x]; int mid = l + r >> 1; if (u <= mid) return find(L[x], l, mid, u); return f[L[x]] + find(R[x], mid + 1, r, u); } void merge(int &x, int y, int l, int r) { if (!x || !y) { x = x^y; return; } f[x] += f[y]; if (l == r) return; int mid = l + r >> 1; merge(L[x], L[y], l, mid); merge(R[x], R[y], mid + 1, r); } int main() { scanf("%d", &T); while (T--) { scanf("%d%lld", &n, &m); l = 1e9, r = 0, tot = 1; rep(i, 1, n) { scanf("%d", &a[i]); cnt[i] = 0; l = min(l, a[i]); r = max(r, a[i]); } rep(i, 1, n - 1) { scanf("%d%d", &x, &y); cnt[x]++; fa[y] = x; } queue<int> p; LL ans = 0; rep(i, 1, n) { make(g[i] = 0, l, r, a[i]); if (!cnt[i]) p.push(i); if (1LL * a[i] * a[i] <= m) ans--; } while (!p.empty()) { int q = p.front(); p.pop(); ans += find(g[q], l, r, m / a[q]); merge(g[fa[q]], g[q], l, r); if (!--cnt[fa[q]]) p.push(fa[q]); } printf("%lld\n", ans); } return 0; }