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

来源:互联网 发布:instagram网络未知错误 编辑:程序博客网 时间:2024/05/21 10:00

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] <= ku 是 v节点的祖先(u != v)

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

这里写图片描述

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

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

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

这里写图片描述

每次寻找两个下标

  1. pos : 大于k / a[v] 对应的第一个下标
  2. 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 restypev ar[N]; // index: 1 ~ Nint 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[N];int cnt;long long ans = 0;long long n,k;int f[N];int a[N];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;}
0 0