题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5877

题意:

weak pair的要求:

1.u是v的祖先(注意不一定是父亲)

2.val[u]*val[k] <=k;

题解:

1.将val(以及k/val)离散化,可用map 或者 用数组。 只要能将val与树状数组或线段树的下标形成映射就可以了。

2.从根节点开始搜索(题目中的树,不是线段树或树状数组的树),先统计当前节点与祖先能形成多少对weak pair,然后将其插入到树状数组或线段树中。

3.递归其子树。递归完子树后,再把当前节点从树状数组或线段树中删去。因为:根据递归的特性,如果不删除,这个值将会残留在c数组, 那么他的堂兄弟,堂叔伯,堂侄子等(后一步 递归的)会误认为这个值是他的祖先的。所以要及时删除。

类似的题(边查询边更新):http://blog.csdn.net/dolfamingo/article/details/71001021

树状数组(map离散)

#include<cstdio>//hdu5877 树状数组 map离散 dfs
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
#define LL long long
#define INF 2e18 using namespace std; LL sval[200020], val[200020];
int n,fa[100010],c[200010];
map<LL,int> m;
vector<int> son[100010];
LL k,ans; int lowbit(int x)
{
    return x & (-x);
} void add(int x, int d)
{
    for(; x<=2*n; x += lowbit(x))
    {
        c[x] += d;
    }
} int sumc(int x)
{
    int s = 0;
    for(;x>0; x -= lowbit(x))
    {
        s += c[x];
    }
    return s;
} void dfs(int rt)//c数组中的下标与val[i],k/val[i]映射 且k/v[i]的下标-i的下边等于n(自己定)
{
    ans += sumc(m[val[n+rt]]);//统计<=k/val[rt]的个数,为什么不直接 m[k/val[rt]]? 因为val[rt]可能为0
    add(m[val[rt]],1);
    for(int i = 0; i<son[rt].size(); i++)
    {
        dfs(son[rt][i]);
    }
    add(m[val[rt]],-1);
} int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%lld",&n,&k);         for(int i = 1; i<=n; i++)
        {
            //存k/val[i]是因为 val[i]*(k/val[i])<= k. 到时可以直接从树状数组中统计<=k/val[i]的个数
            scanf("%lld",&val[i]);
            if(val[i])
                val[n+i] = k/val[i];
            else            //0为特殊情况
                val[n+i] = INF;
        }          //sval的作用是将v值按从小到大,一一与c数组的下标形成映射
        for(int i = 1; i<=2*n; i++)
            sval[i] = val[i];
        sort(sval+1,sval+2*n+1);         int cnt = 0;
        m.clear();
        for(int i = 1; i<=2*n; i++)
        {
            //map的作用是将v值与c数组的下标形成映射
            if(!m[sval[i]]) m[sval[i]] = ++cnt;
        }         for(int i = 1; i<=n; i++)
            fa[i] = 0, son[i].clear();
        for(int i = 1,u,v; i<n; i++)
        {
            scanf("%d%d",&u,&v);
            son[u].push_back(v);
            fa[v] = u;
        }         ans = 0;
        memset(c,0,sizeof(c));
        for(int i = 1; i<=n; i++)
        {
            if(!fa[i])
            {
                dfs(i);
                break;
            }
        }
        printf("%lld\n",ans);     }
    return 0;
}

线段树(map离散):

#include<cstdio>//hdu5877 线段树 map离散 dfs
#include<cstring>//注意区分题目的树和线段树的树
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#define LL long long
#define INF 2e18 using namespace std; int n,len;//n是题目给出的树的结点个数,len是线段树的线段长度。
LL k,ans;
LL val[200100],sval[200100];//val记录原始值,sval记录经过排序,删除重复操作的值,用于线段树的操作
int fa[100100],sum[800100];
vector<int>son[100100];
map<LL,int>m; int query(int root, int le, int ri, int x, int y)
{
if(x<=le && y>=ri)
return sum[root]; int mid = (le+ri)/2, ret = 0;
if(x<=mid) ret += query(root*2,le,mid,x,y);
if(y>=mid+1) ret += query(root*2+1,mid+1,ri,x,y);
return ret;
} void update(int root, int le, int ri, int pos, int d)
{
if(le==ri)
{
sum[root] += d;
return;
} int mid = (le+ri)/2;
if(pos<=mid) update(root*2,le,mid,pos,d);
else update(root*2+1,mid+1,ri,pos,d);
sum[root] = sum[root*2] + sum[root*2+1];
} void dfs(int rt)
{
int last = m[val[n+rt]];
int pos = m[val[rt]]; ans += query(1,1,len,1,last); update(1,1,len,pos,1);
for(int i = 0; i<son[rt].size(); i++)
{
dfs(son[rt][i]);
}
update(1,1,len,pos,-1);
} int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%lld",&n,&k);
for(int i = 1; i<=n; i++)
{
scanf("%lld",&val[i]);
if(val[i])
val[n+i] = k/val[i];
else
val[n+i] = INF;
} for(int i = 1; i<=2*n; i++)
sval[i] = val[i];
sort(sval+1,sval+2*n+1); m.clear();
len = 0;
for(int i = 1; i<=2*n; i++)
{
if(!m[sval[i]]) m[sval[i]] = ++len;
} for(int i = 1; i<=n; i++)
fa[i] = 0, son[i].clear();
for(int i = 1,u,v; i<n; i++)
{
scanf("%d%d",&u,&v);
son[u].push_back(v);
fa[v] = u;
} ans = 0;
memset(sum,0,sizeof(sum));
for(int i = 1; i<=n; i++)
{
if(!fa[i])
{
dfs(i);
break;
}
} printf("%lld\n",ans);
}
return 0;
}

线段树(数组离散):

#include<cstdio>//hdu5877 线段树 dfs 普通数组进行离散
#include<cstring>//注意区分题目的树和线段树的树
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<vector>
#define LL long long
#define INF 2e18
using namespace std; int n,m;//n是题目给出的树的结点个数,m是线段树的线段长度。
LL k,ans;
LL val[200100],sval[200100];//val记录原始值,sval记录经过排序,删除重复操作的值,用于线段树的操作
int fa[100100],sum[800100];
vector<int>son[100100]; int query(int root, int le, int ri, int x, int y)
{
if(x<=le && y>=ri)
return sum[root]; int mid = (le+ri)/2, ret = 0;
if(x<=mid) ret += query(root*2,le,mid,x,y);
if(y>=mid+1) ret += query(root*2+1,mid+1,ri,x,y);
return ret;
} void update(int root, int le, int ri, int pos, int d)
{
if(le==ri)
{
sum[root] += d;
return;
} int mid = (le+ri)/2;
if(pos<=mid) update(root*2,le,mid,pos,d);
else update(root*2+1,mid+1,ri,pos,d);
sum[root] = sum[root*2] + sum[root*2+1];
} void dfs(int rt)
{
int last = lower_bound(sval+1, sval+m+1,val[n+rt]) - sval;
int pos = lower_bound(sval+1,sval+m+1,val[rt]) - sval; ans += query(1,1,m,1,last); update(1,1,m,pos,1);
for(int i = 0; i<son[rt].size(); i++)
{
dfs(son[rt][i]);
}
update(1,1,m,pos,-1);
} int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%lld",&n,&k);
for(int i = 1; i<=n; i++)
{
scanf("%lld",&val[i]);
if(val[i])
val[n+i] = k/val[i];
else
val[n+i] = INF;
} for(int i = 1; i<=2*n; i++)
sval[i] = val[i];
sort(sval+1,sval+2*n+1);
m = unique(sval+1,sval+2*n+1) - (sval+1); for(int i = 1; i<=n; i++)
fa[i] = 0, son[i].clear();
for(int i = 1,u,v; i<n; i++)
{
scanf("%d%d",&u,&v);
son[u].push_back(v);
fa[v] = u;
} ans = 0;
memset(sum,0,sizeof(sum));
for(int i = 1; i<=n; i++)
{
if(!fa[i])
{
dfs(i);
break;
}
} printf("%lld\n",ans);
}
return 0;
}

HDU5877 Weak Pair dfs + 线段树/树状数组 + 离散化的更多相关文章

  1. hdu4605 树状数组+离散化+dfs

    Magic Ball Game Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) ...

  2. POJ 2299 【树状数组 离散化】

    题目链接:POJ 2299 Ultra-QuickSort Description In this problem, you have to analyze a particular sorting ...

  3. BZOJ_5055_膜法师_树状数组+离散化

    BZOJ_5055_膜法师_树状数组+离散化 Description 在经历过1e9次大型战争后的宇宙中现在还剩下n个完美维度, 现在来自多元宇宙的膜法师,想偷取其中的三个维度为伟大的长者续秒, 显然 ...

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

    题目链接 http://acm.split.hdu.edu.cn/showproblem.php?pid=5877 Problem Description You are given a rooted ...

  5. HDU - 5877 Weak Pair (dfs+树状数组)

    题目链接:Weak Pair 题意: 给出一颗有根树,如果有一对u,v,如果满足u是v的父节点且vec[u]×vec[v]<=k,则称这对结点是虚弱的,问这棵树中有几对虚弱的结点. 题解: 刚开 ...

  6. hdu 5877 Weak Pair dfs序+树状数组+离散化

    Weak Pair Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Prob ...

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

    http://acm.hdu.edu.cn/listproblem.php?vol=49 给定一颗树,然后对于每一个节点,找到它的任何一个祖先u,如果num[u] * num[v] <= k.则 ...

  8. 线段树合并 || 树状数组 || 离散化 || BZOJ 4756: [Usaco2017 Jan]Promotion Counting || Luogu P3605 [USACO17JAN]Promotion Counting晋升者计数

    题面:P3605 [USACO17JAN]Promotion Counting晋升者计数 题解:这是一道万能题,树状数组 || 主席树 || 线段树合并 || 莫队套分块 || 线段树 都可以写..记 ...

  9. LightOJ 1085(树状数组+离散化+DP,线段树)

    All Possible Increasing Subsequences Time Limit:3000MS     Memory Limit:65536KB     64bit IO Format: ...

随机推荐

  1. Network | Public-key cryptography

    公开密钥加密public-key cryptography,也称为非对称(密钥)加密. 非对称密钥,是指一对加密密钥与解密密钥,这两个密钥是数学相关,用某用户密钥加密后所得的信息,只能用该用户的解密密 ...

  2. 空扫描Idle Scanning

    空扫描Idle Scanning   空扫描Idle Scanning是一种借助第三方实施的端口扫描技术,可以很好的隐蔽扫描主机本身.它的实现基于以下两个TCP工作机制.   (1)在TCP三次握手阶 ...

  3. SRM1154--Topcoder初体验

    SRM 711 DIV2 <br > 在frank_c1的帮助下,辣鸡Xiejiadong也开始做Topcoder辣...... <br > 这算是一次Topcoder的初体验 ...

  4. hadoop之hdfs及其工作原理

    hadoop之hdfs及其工作原理 (一)hdfs产生的背景 随着数据量的不断增大和增长速度的不断加快,一台机器上已经容纳不下,因此就需要放到更多的机器中,但这样做不方便维护和管理,因此需要一种文件系 ...

  5. Ubuntu下添加开机启动项的2种方法

    1.方法一,编辑rc.loacl脚本 Ubuntu开机之后会执行/etc/rc.local文件中的脚本,所以我们可以直接在/etc/rc.local中添加启动脚本.当然要添加到语句:exit 0 前面 ...

  6. mac os+selenium2+chrome驱动+python3

    mac os 10.11.5 mac自带python2.7,自己下载了python3.5,pip list查看系统中的安装包,本人电脑中已经安装了pip和setuptools,若未安装,请先使用 su ...

  7. Delphi图像处理 -- 颜色矩阵变换

    转载自阿发伯:http://blog.csdn.net/maozefa/article/details/8316430 阅读提示:     <Delphi图像处理>系列以效率为侧重点,一般 ...

  8. 第九讲_图像生成 Image Captioning

    第九讲_图像生成 Image Captioning 生成式对抗网络 Generative Adversarial network 学习数据分布:概率密度函数估计+数据样本生成 生成式模型是共生关系,判 ...

  9. LattePanda 项目之 P2.2 起飞条件检测系统(CLI & GUI)

    前言 原创文章,转载引用务必注明链接,水平有限,如有疏漏,欢迎指正. 本文使用Markdown写成,为获得更好的阅读体验和正常的链接.图片显示,请访问我的博客原文: http://www.cnblog ...

  10. OpenCV for Python 学习笔记 一

    本人的学习笔记主要记录的是学习opencv-python-tutorials这本书中的笔记 今天晚上简单学习OpenCV for Python如何绘图,主要用了这几个函数(这几个函数可在:http:/ ...