HDU - 5877 Weak Pair —— 线段树 dfs序 离散化

Weak Pair

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 4455    Accepted Submission(s): 1297


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×avk.

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: 
  
   1N105 
  
   0ai109 
  
   0k1018
 

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

题意:

给定有n个节点的树,每个节点有一个值ai,问满足下列两个条件的节点对(u,v)有多少

①u是v的父节点(在本题中u不是u的父节点)

②au*av?<=k

思路:

与子树有关->dfs序

点的ai值过大->离散化

快速查询更改父节点->线段树(树状数组)

线段树维护的是当前已经遍历过的父节点的个数

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <cmath>
#include <vector>
#define max_ 101000
#define inf 0x3f3f3f3f
#define ll long long
#define les 1e-8
using namespace std;
struct node
{
    int l,r;
    int w;
};
struct node tree[max_*80];
int n,l;
ll k,ans;
ll num[max_*2];
ll val[max_];
vector<int>v[max_];
bool vis[max_];
void built(int i,int l,int r)
{
    tree[i].l=l;
    tree[i].r=r;
    tree[i].w=0;
    if(l==r)
    return;
    int mid=(l+r)>>1;
    built(i<<1,l,mid);
    built(i<<1|1,mid+1,r);
}
ll query(int i,int l,int r)
{
    if(tree[i].l==l&&tree[i].r==r)
    return (ll)tree[i].w;
    int mid=(tree[i].l+tree[i].r)>>1;
    if(r<=mid)
    return query(i<<1,l,r);
    else if(l>mid)
    return query(i<<1|1,l,r);
    else
    return query(i<<1,l,mid)+query(i<<1|1,mid+1,r);
}
void updata(int i,int k,int v)
{
    if(tree[i].l==tree[i].r)
    {
        tree[i].w+=v;
        return;
    }
    int mid=(tree[i].l+tree[i].r)>>1;
    if(k<=mid)
    updata(i<<1,k,v);
    else
    updata(i<<1|1,k,v);
    tree[i].w=tree[i<<1].w+tree[i<<1|1].w;
}
void dfs(int x)
{
    int q=lower_bound(num+1,num+l,k/val[x])-num;//要寻找的ai值在num数组中的位置
    int p=lower_bound(num+1,num+l,val[x])-num;//当前遍历到的父节点在num数组中的位置
    ans+=query(1,1,q);//查询在1~ai之间已经有多少个满足条件的父节点
    updata(1,p,1);//将当前父节点加入
    for(int i=0;i<v[x].size();i++)
    dfs(v[x][i]);
    updata(1,p,-1);//子树已经搜索完毕,将当前父节点弹出
}
int main(int argc, char const *argv[]) {
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%lld",&n,&k);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&num[i]);
            val[i]=num[i];
            v[i].clear();
        }
        for(int i=n+1;i<=2*n;i++)
            num[i]=k/(num[i-n]);
        sort(num+1,num+1+n*2);
        l=unique(num+1,num+1+2*n)-(num+1);//离散化
        built(1,1,l);
        memset(vis,false,sizeof vis);
        for(int i=1;i<n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            v[x].push_back(y);
            vis[y]=true;
        }
        int root;
        for(int i=1;i<=n;i++)
        {
            if(vis[i]==false)//没有在子节点中出现过的就是根节点
            {
                root=i;
                break;
            }
        }
        ans=0;
        dfs(root);
        printf("%lld\n",ans );
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值