题目:Weak Pair
链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5877
题意:给一棵树和一个定值k,每个点的值w,对于两点(u、v),如果u 是v 的祖先,且w[u]*w[v]<=k,则说u、v是弱的,问树中有多少对u、v是弱的。
思路:
第一个要求u 是v 的祖先,那么可以dfs,遍历到v时,所有他上方的都是满足第一条件的u,做多了树就很容易想到在退出某个子树的时候消除这个影响,这样就能保证所有有影响的都是祖先。要求w[u]*w[v]<=k,那么到v的时候,所有小于等于k/w[v]的u都满足,可以想到树状数组。结点的值最大10亿,肯定要离散化,离散化的时候要把k/w[v]加进去一起离散。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include <vector>
#include <queue>
using namespace std;
#define LL long long
#define INF 0x3f3f3f3f3f3f3f3f
int T;
int n,m;
LL k;
LL a[110000];
int in[110000];
int u,v,s;
LL b[220000];
LL ans;
vector<int> G[110000];
int id(LL num)
{
return lower_bound(b+1,b+1+2*n,num)-b;
}
LL c[420000];
void init()
{
memset(c,0,sizeof(c));
}
int lowbit(int x)
{
return x&(-x);
}
void add(int pos,LL val)
{
int x = id(a[pos]);
while(x<=2*n+1)
{
c[x] +=val;
x += lowbit(x);
}
}
LL sum(int x)
{
LL sum=0;
while(x>0)
{
sum = sum + c[x];
x -=lowbit(x);
}
return sum;
}
LL solve(int pos)
{
int x;
if(a[pos]==0) x=2*n+1;
else x = id(k/a[pos]);
return sum(x);
}
void dfs(int pos)
{
ans = ans + solve(pos);
add(pos,1);
int sz = G[pos].size();
for(int i=0;i<sz;i++)
{
dfs(G[pos][i]);
}
add(pos,-1);
}
int main()
{
scanf("%d",&T);
while(T--)
{
//init();
scanf("%d%lld",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
G[i].clear();
in[i]=0;
}
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
G[u].push_back(v);
in[v]=1;
}
int s;
for(int i=1;i<=n;i++)
{
if(in[i]==0) {s=i;break;}
}
for(int i=1;i<=n;i++)
{
b[i] = a[i];
if(a[i]!=0) b[i+n] = k/a[i];
else b[i+n] = INF;
}
sort(b+1,b+1+2*n);
ans=0;
dfs(s);
printf("%lld\n",ans);
}
return 0;
}