Weak Pair (dfs+树状数组)
题意
这个题目是要求:一颗树上,有n个节点,给出每个节点的权值。另外给出一个值k,问有多少对节点满足:
- \(power[u]*power[v]<=k\)
- u是v节点的祖先(u不等于v)
解题思路
这个可以找父节点权值满足小于或者等于\(\frac{k}{power[v]}\)(注意这里可能不能够整除)
我们从根节点出发,一个一个地遍历,走到一个节点就看它前面的父节点有没有符合条件的。这个可以使用树状数组来进行求解,在已经去完重和排好序的数组中查找满足条件节点的位置,和当前节点的位置,注意这里使用的是upper_bound,因为上面的条件可能不能够整除,使用lower_bound不够精确。
代码实现
#include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<vector> using namespace std; typedef long long ll; const ll inf=1e18; const int maxn=1e5+7; vector<int> g[maxn]; int sum[maxn]; ll power[maxn]; ll lishan[maxn]; int vis[maxn]; int n, cnt, ans; ll k; int lowbit(int x) { return x&(-x); } int update(int x, int v) { while(x<=cnt+1) { sum[x]+=v; x+=lowbit(x); } } int getsum(int x) { int ret=0; while(x>0) { ret+=sum[x]; x-=lowbit(x); } return ret; } void dfs(int rt) { int len=g[rt].size(); int pos; if(power[rt]==0) pos=cnt+1; else pos=upper_bound(lishan+1, lishan+cnt+1, k/power[rt])-(lishan); int posthis=upper_bound(lishan+1, lishan+cnt+1, power[rt])-(lishan); ans+=getsum(pos); update(posthis, 1); for(int i=0; i<len; i++) { dfs(g[rt][i]); } update(posthis, -1); } void init() { ans=0; for(int i=0; i<=n; i++) { vis[i]=0; g[i].clear(); sum[i]=0; } } int main() { int t; scanf("%d", &t); while(t--) { scanf("%d%lld", &n, &k); init(); for(int i=1; i<=n; i++) { scanf("%lld", &power[i]); lishan[i]=power[i]; } sort(lishan+1, lishan+n+1); cnt=unique(lishan+1, lishan+n+1)-(lishan+1); int a, b; for(int i=1; i<n; i++) { scanf("%d%d", &a, &b); g[a].push_back(b); vis[b]=1; } for(int i=1; i<=n; i++) { if(!vis[i]) { dfs(i); break; } } printf("%d\n", ans); } return 0; }