大连网络赛--Weak Pair--离散化+树状数组+DFS

Weak Pair

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


 

Problem Description

You are given a rooted tree of N nodes, labeled from 1 to N . To the i th 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

 

 

Source

2016 ACM/ICPC Asia Regional Dalian Online

 

 

Recommend

wange2014

首先离散化,然后把每一个ai和k/ai都离散化,加入数组,然后排序。接着深搜,对于每一个点,到达它时它的祖先一定到达过,所以利用树状数组,统计在它之前比k/ai小于或等于的数,然后更新。

参考:https://blog.csdn.net/queuelovestack/article/details/52505856

#include <algorithm>    //STL通用算法
#include <bitset>     //STL位集容器
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex>     //复数类
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>      //STL双端队列容器
#include <exception>    //异常处理类
#include <fstream>
#include <functional>   //STL定义运算函数(代替运算符)
#include <limits>
#include <list>      //STL线性列表容器
#include <map>       //STL 映射容器
#include <iomanip>
#include <ios>      //基本输入/输出支持
#include<iosfwd>     //输入/输出系统使用的前置声明
#include <iostream>
#include <istream>     //基本输入流
#include <ostream>     //基本输出流
#include <queue>      //STL队列容器
#include <set>       //STL 集合容器
#include <sstream>    //基于字符串的流
#include <stack>      //STL堆栈容器    
#include <stdexcept>    //标准异常类
#include <streambuf>   //底层输入/输出支持
#include <string>     //字符串类
#include <utility>     //STL通用模板类
#include <vector>     //STL动态数组容器
#include <cwchar>
#include <cwctype>
#define ll long long
using namespace std;
priority_queue<int,vector<int>,less<int> >q;
int dx[]= {-1,1,0,0,-1,-1,1,1};
int dy[]= {0,0,-1,1,-1,1,1,-1};
const int maxn = 100000+66;
const ll mod=10007;
const ll INF =1e18+2;
ll n,k;
ll a[maxn];
ll b[maxn*2];
struct Edge
{
    ll from;
    ll to;
    ll next;
} e[maxn];
int tot;
int head[maxn];
void Add_Edge(int u,int v,int *head)
{
    e[++tot].to=v;
    e[tot].from=u;
    e[tot].next=head[u];
    head[u]=tot;
}
ll ans;
int len;
ll c[maxn*2];
int lowbit(int x)
{
    return x&(-x);
}
ll Sum(int x)
{
    ll sum=0;
    while(x>0)
    {
        sum+=c[x];
        x-=lowbit(x);
    }
    return sum;
}
void Update(int x,ll v)
{
    while(x<=len)
    {
        c[x]=c[x]+v;
        x+=lowbit(x);
    }
}
void dfs(ll x)
{
    ans+=Sum(lower_bound(b,b+len,a[x]?k/a[x]:INF)-b+1);
    //cout<<Sum(lower_bound(b,b+len,a[x]?k/a[x]:INF)-b+1)<<"---"<<endl;
    Update(lower_bound(b,b+len,a[x])-b+1,1);
    for(int i=head[x];i;i=e[i].next)
    {
        ll v=e[i].to;
        dfs(v);
    }
    Update(lower_bound(b,b+len,a[x])-b+1,-1);
}
bool vis[maxn];
void init()
{
    tot=0;
    ans=0;
    len=0;
    memset(head,0,sizeof(head));
    memset(c,0,sizeof(c));
    memset(vis,false,sizeof(vis));
    memset(e,0,sizeof(e));
    memset(b,0,sizeof(b));
}
int main()
{
    int t;
    while(scanf("%d",&t)!=EOF)
    {
        while(t--)
        {
            init();
            scanf("%lld %lld",&n,&k);
            for(int i=1; i<=n; i++)
            {
                scanf("%lld",&a[i]);
                b[len++]=a[i];
                if(a[i]!=0)
                {
                    b[len++]=k/a[i];
                }
                else
                {
                    b[len++]=INF;
                }
            }
            sort(b,b+len);
            len=unique(b,b+len)-b;
            for(int i=1; i<n; i++)
            {
                ll u,v;
                scanf("%lld %lld",&u,&v);
                vis[v]=true;
                Add_Edge(u,v,head);
            }
            for(int i=1; i<=n; i++)
            {
                if(!vis[i])
                {
                    dfs(i);
                }
            }
            printf("%I64d\n",ans);
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值