2016 大连网赛---Weak Pair(dfs+树状数组)

题目链接

http://acm.split.hdu.edu.cn/showproblem.php?pid=5877

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

题意:输入n,k  表示有n个节点的一棵树,然后输入n个节点的权值和n-1条边,求点对(u,v)的对数,满足:

1、u是v的祖先节点。

2、a[u]*a[v]<=k,a[]是存储权值的数组。

思路:从根节点开始向下深搜,每到一个点时计算sum+=Sum(a[i]),Sum(x)表示大于等于x的个数,然后向树状数组中加入k/a[i],继续递归深搜,退栈时从树状数组中减去k/a[i] ,这样可以保证树状数组中存的一直是一条到根节点的路径值。大题思路如上,这里要做一个离散化的处理,输入的权值<=1e9  k<=1e18  而只有1e5个点,所以可以离散到2*1e5 后处理;

题解中提示用treap计算大于等于x的个数,这样可以不需要进行离散化;

第一次自己做出深搜的题,挺高兴的^_^  看样子我对深搜有了一点认识了

代码如下:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <map>
using namespace std;
const long long maxn=200003;
long long root;
long long sum,k;
long long in[100005];
vector<long long>g[100005];
long long a[100005];
long long b[200005];

long long c[200005];
map<long long,long long>q;

long long Lowbit(long long t)
{
    return t&(t^(t-1));
}
void add(long long x,long long t)
{
    while(x > 0)
    {
        c[x]+=t;
        x -= Lowbit(x);
    }
}
long long Sum(long long li)
{
    long long s=0;
    while(li<200005)
    {
        s+=c[li];
        li=li+Lowbit(li);
    }
    return s;
}

void dfs(long long t)
{
    long long n=g[t].size();
    for(long long i=0;i<n;i++)
    {
        long long v=g[t][i];
        sum+=(long long)Sum(q[a[v]]);
        if(a[v]==0) add(maxn,1);
        else   add(q[k/a[v]],1);
        dfs(v);
        if(a[v]==0) add(maxn,-1);
        else   add(q[k/a[v]],-1);
    }
}

int main()
{
    long long T,N;
    scanf("%lld",&T);
    while(T--)
    {
        q.clear();
        memset(in,0,sizeof(in));
        memset(c,0,sizeof(c));
        memset(b,0,sizeof(b));
        scanf("%lld%lld",&N,&k);
        for(long long i=1;i<=N;i++)
        {
            scanf("%lld",&a[i]);
            b[2*i-2]=a[i];
            if(a[i]!=0)
            b[2*i-1]=k/a[i];
            g[i].clear();
        }
        sort(b,b+2*N);
        long long tot=0,pre=-1;
        for(long long i=0;i<2*N;i++)
        {
            if(b[i]!=pre)
            {
                pre=b[i];
                q[pre]=++tot;
            }
        }
        for(long long i=0;i<N-1;i++)
        {
            long long aa,bb;
            scanf("%lld%lld",&aa,&bb);
            g[aa].push_back(bb);
            in[bb]++;
        }
        for(long long i=1;i<=N;i++)
        if(in[i]==0) { root=i; break; }

        sum=0;
        if(a[root]==0) add(maxn,1);
        else   add(q[k/a[root]],1);
        dfs(root);
        printf("%lld\n",sum);
    }
    return 0;
}
时间: 2024-12-28 08:13:13

2016 大连网赛---Weak Pair(dfs+树状数组)的相关文章

HDU 5877 Weak Pair DFS + 树状数组 + 其实不用离散化

http://acm.hdu.edu.cn/listproblem.php?vol=49 给定一颗树,然后对于每一个节点,找到它的任何一个祖先u,如果num[u] * num[v] <= k.则贡献加1 思路:主要的麻烦就是动态修改前缀和了.因为对于每个数字val.则找它祖先的话, <= k / val的数字,都是合法的.所以问题转化成求你现在dfs中保存的数字,有多少个是  <= k / val的,树状数组即可. 问题就是,数字太大了,这不适合树状数组,那么我们把每个数字离散成他们的下

HDU 5877 Weak Pair(树状数组+dfs+离散化)

http://acm.hdu.edu.cn/showproblem.php?pid=5877 题意: 给出一棵树,每个顶点都有权值,现在要你找出满足要求的点对(u,v)数,u是v的祖先并且a[u]*a[v]<=k. 思路: 转化一下,a[v]<=k/a[u],k/a[u]的最大值也就是k/a[v],也就是寻找<=k/a[v]的个数,到这儿,是不是很像树状数组? 我们只需要从根开始dfs,插入到树状数组中,并且查询即可.注意这道题目需要离散化一下. 1 #include <iostr

2016大连网络赛 Weak Pair

Weak Pair Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 333    Accepted Submission(s): 111 Problem Description You are given a rooted tree of N nodes, labeled from 1 to N. To the ith node a

13杭州区域赛现场赛Rabbit Kingdom(树状数组+离线)

题意:给你一个长度数列,再给你m个询问(一个区间),问你在这个区间里面有多少个数与其他的数都互质. 解题思路:你看这种类型的题目都可以肯定这是 离线+树状数组(线段树).主要就是他的更新信息.这里我的处理是先把1-200000(每个数的范围)数里面所有的质因子求出来.然后从后往前遍历数组.会出现以下几种情况 1.a[k]的质因子在后面出现过而[更新标记] 和[被更新标记] 都为假 2.a[k]的质因子在后面出现过的那个位置 I   [更新标记]为 真 . 3.a[k]的质因子在后面出现过且那个位

2016大连网赛

网赛的时候就是前三个小时过了后面五道,然后两个小时就没搞出啥了;账号密码都忘了,只好重新写一遍了; hdu-5868 hdu-5869 hdu-5870 hdu-5871 hdu-5872 hdu-5873 hdu-5874 hdu-5875 hdu-5876 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath>

POJ3321Apple Tree【dfs 树状数组】

题目大意:一棵树(不一定是二叉树!!),树的节点上本来都有一个苹果,要求完成以下操作: 1.指定某个节点,如果这个节点原本有苹果则拿去,如果没有苹果则填上一个苹果 2.询问某个节点以及其子树一共有多少个苹果 思路:dfs这棵树,记录下第一次到达这个节点的时间以及遍历离开的时间,于是一个节点就成了一个区间,左端点和右端点分别是开始遍历的时间和结束遍历的时间,区间里夹着的就是这个节点的子树!!区间端点记录有没有苹果,这样问题就变成了询问一个区间和的问题,而加减苹果就是对区间端点+1和-1 这两个操作

2016 大连网赛

总结:弱爆了,一题都没做出 1006   Football Games    HDU 5873 1.题意:团队比赛,赢的+2,输的+0,平+1.给出最后分数,看是否符合. 2.总结:好像是有个定理判定这种序列, s?1??+s?2??+...+s?i??≥i(i−1),对于所有1≤i≤n−1s?1??+s?2??+...+s?n??=n(n−1),对于i==n #include<iostream> #include<cstring> #include<cmath> #i

青出于蓝胜于蓝 dfs+树状数组

武当派一共有 nn 人,门派内 nn 人按照武功高低进行排名,武功最高的人排名第 11,次高的人排名第 22,... 武功最低的人排名第 nn.现在我们用武功的排名来给每个人标号,除了祖师爷,每个人都有一个师父,每个人可能有多个徒弟. 我们知道,武当派人才辈出,连祖师爷的武功都只能排行到 pp.也就是说徒弟的武功是可能超过师父的,所谓的青出于蓝胜于蓝. 请你帮忙计算每个人的所有子弟(包括徒弟的徒弟,徒弟的徒弟的徒弟....)中,有多少人的武功超过了他自己. 输入格式 输入第一行两个整数 n, p

【poj1901-求区间第k大值(带修改)】树状数组套主席树

901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 7025  Solved: 2925[Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]--a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]