您的位置:首页 > 理论基础 > 计算机网络

HDU-5877-Weak Pair【树状数组】【离散化】【DFS】【2016大连网络】【好题】

2016-09-30 17:44 411 查看

HDU-5877-Weak Pair

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?

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

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

题目链接:HDU-5877

题目大意:一颗树上,有n个节点,给出每个节点的权值。另外给出一个值k,问有多少对节点满足:

a[u] * a[v] <= k
u 是 v节点的祖先(u != v)


题目思路:我们先考虑,红色节点为V,那么U为V的所有祖先节点中权值小于k / a[v] 都满足。



我们用一个数组记录当前节点,所有祖先的情况。

因为每次遍历所有祖先寻找小于k / a[v]的 必然超时,所以想到利用树状数组,计算值k / a[v]之前的和即可。这里需要进行离散化处理。

例如,所有存在的权值为 2 3 5, 那么



每次寻找两个下标

pos : 大于k / a[v] 对应的第一个下标

posthis : 等于a[v]的下标

ans += getsum(pos); // 即找到了当前节点为a[v],前面祖先节点有几个小于k / a[v]的值

add(posthis,1); //当前节点是下面节点的父节点

add(posthis,-1); //退出

以下是代码:

#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <functional>
#include <numeric>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <vector>
#include <queue>
#include <deque>
#include <list>

using  namespace std;

/*一维数状数组*/
#define N 200005
#define typev int // type of res
typev ar
; // index: 1 ~ N
int lowb(int t)
{
return t & (-t) ;
}

void add(int i, typev v)
{
for ( ; i < N; ar[i] += v, i += lowb(i));
}

typev getsum(int i)
{
typev s = 0;
for ( ; i > 0; s += ar[i], i -= lowb(i));
return s;
}
struct node
{
vector <int> cld;
}tree
;
int cnt;
long long ans = 0;
long long n,k;
int f
;
int a
;
map <int,int> vis;
vector <int> vec;
void solve(int root)
{
int len = tree[root].cld.size();
int pos = upper_bound(vec.begin(), vec.end(), k / a[root]) - vec.begin();  //前面的值需小于等于tmp才符合a[u] * a[v] <= k
int posthis = lower_bound(vec.begin(), vec.end(), a[root]) - vec.begin();  //当前这个数在哪个位置

ans += getsum(pos);  //把前面符合条件的个数加起来

add(posthis + 1, 1);

for (int i = 0; i < len; i++)
{
solve(tree[root].cld[i]);
}
add(posthis + 1, -1);
}
void init()
{
cnt = 1;
ans = 0;
vec.clear();
vis.clear();
for (int i = 0; i < 200003; i++)
{
tree[i].cld.clear();
f[i] = 0;
ar[i] = 0;
}
}
int main()
{
int t;
cin >> t;
while(t--)
{
init();

scanf("%lld%lld",&n,&k);
for (int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
if (!vis[a[i]]) //离散化
{
vis[a[i]] = 1;
vec.push_back(a[i]);  //记录有哪些种权值
}
}
sort(vec.begin(), vec.end());
for (int i = 1; i < n; i++)
{
int u,v;
cin >> u >> v;
tree[u].cld.push_back(v);
f[v] = 1;  //标记v不是根节点
}
for (int i = 1; i <= n; i++)
{
if (!f[i])
{
solve(i);
break;
}
}
printf("%lld\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  HDU 5877 树状数组 DFS