题目链接 Weak Pair
题意十分明确, 就是求出符合题意的有序点对个数。
首先对ai离散,离散之后的结果用rk[i]表示,然后进行二分预处理得到f[i],其中f[i]的意义为:其他的点和i这个节点满足weakpair要求的权值最大名次(名次权值小的排在前面)。
然后就开始跑一遍DFS,树状数组维护一下答案,就好了。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for(int i(a); i <= (b); ++i) #define dec(i, a, b) for(int i(a); i >= (b); --i) #define for_edge(i,x) for(int i = H[x]; i; i = X[i]) #define LL long long const int N = 300000 + 10; struct Node{ LL num; int id; friend bool operator < (const Node &a, const Node &b){ return a.num < b.num; } } tree[N]; int E[N << 1], X[N << 1], H[N << 1]; LL a[N]; int T, et; int n; LL k; int x, y; LL rk[N], f[N]; LL now; int l, r; bool pa[N]; int root; LL c[N]; LL ans; bool v[N]; inline void addedge(int a, int b){ E[++et] = b, X[et] = H[a], H[a] = et; } inline void add(LL x, LL val){ for (; x <= n; x += (x) & (-x)) c[x] += val; } inline LL query(LL x){ LL ret(0); for (; x; x -= (x) & (-x)) ret += c[x]; return ret; } void dfs(int x){ add(rk[x], 1); for_edge(i, x) if (!v[E[i]]) dfs(E[i]), v[E[i]] = true; add(rk[x], -1); ans += query(f[x]); } int main(){ scanf("%d", &T); while (T--){ et = 0; scanf("%d%lld", &n, &k); rep(i, 1, n) scanf("%lld", a + i); memset(v, false, sizeof v); memset(pa, true, sizeof pa); memset(tree, 0, sizeof tree); memset(H, 0, sizeof H); rep(i, 1, n - 1){ scanf("%d%d", &x, &y); addedge(x, y); pa[y] = false; } rep(i, 1, n){ tree[i].num = a[i]; tree[i].id = i; } sort(tree + 1, tree + n + 1); rk[tree[1].id] = 1; rep(i, 2, n) if (tree[i].num == tree[i - 1].num) rk[tree[i].id] = rk[tree[i - 1].id]; else rk[tree[i].id] = rk[tree[i - 1].id] + 1; rep(i, 1, n){ now = k / a[i]; l = 1; r = n; if (tree[1].num > now) f[i] = 0; else{ while (l + 1 < r){ int mid = (l + r) >> 1; if (tree[mid].num <= now) l = mid; else r = mid - 1; } if (tree[r].num <= now) l = r; f[i] = rk[tree[l].id]; } } root = 0; rep(i, 1, n) if (pa[i]){ root = i; break;} memset(c, 0, sizeof c); ans = 0; v[root] = true; dfs(root); printf("%lld ", ans); } return 0; }