http://acm.hdu.edu.cn/listproblem.php?vol=49

给定一颗树,然后对于每一个节点,找到它的任何一个祖先u,如果num[u] * num[v] <= k。则贡献加1

思路:主要的麻烦就是动态修改前缀和了。因为对于每个数字val。则找它祖先的话, <= k / val的数字,都是合法的。所以问题转化成求你现在dfs中保存的数字,有多少个是  <= k / val的,树状数组即可。

问题就是,数字太大了,这不适合树状数组,那么我们把每个数字离散成他们的下标即可,但其实这部的操作是不需要的,就是不需要用map来离散的,因为一个数组a[],排序后的数组b[],b[i]就是a[]中某一个数字,那么i就是其对应离散后的下标,怎么找这个下标呢?lower_bound即可。但是,有相同的数字的话,lower_bound总是会找第一的,就是2 2 2 2,你找2,返回的是1的。但是没事,这不影响我们的结果。

所以,lower_bound即可,然后找到有多少个数是 <= k / val的,首先找到k / val离散后的下标,那么问题来了,没有k / val这个数值怎么办?那么就找到第一个 <= k / val的就好了。int pos = upper_bound - 1; 。这个不能用lower_bound来找下标了,为什么呢,因为它可能不存在,所以找到一个比它大的了,如果存在,那刚好,不存在又蛋疼,所以用upper_bound找,-1即可。

这题比赛的时候想到怎么做,但是写不出,然后赛后也写了很久,主要是dfs那么什么时候更新,什么时候取消更新,有点乱,还是太渣了啊。。。努力吧

我dfs的思路是这样的:首先没到一个节点cur。算贡献,然后这个节点入树状数组,然后当这个节点的所有边遍历完后,把这个数删除,注意一点是数字可能有0,不能除。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const int maxn = 1e5 + ;
LL a[maxn];
LL b[maxn];
int n;
LL k;
struct edge {
int u, v;
int tonext;
} e[maxn];
int num, first[maxn];
bool in[maxn];
void addedge(int u, int v) {
++num;
e[num].u = u;
e[num].v = v;
e[num].tonext = first[u];
first[u] = num;
}
LL ans;
int c[maxn];//
int lowbit (int x) { //
return x&(-x);
}
void add (int pos,int val) { //
if (pos <= ) return;
while (pos<=n) { //
c[pos] += val;
pos += lowbit(pos);
}
return ;
}
int get_sum (int pos) { //???1--pos???
if (pos <= ) return ;
int ans = ;
while (pos) {
ans += c[pos];
pos -= lowbit(pos);
}
return ans;
}
void calc(int cur) {
if (a[cur] == ) {
ans += get_sum(n);
} else {
LL tofind = k / a[cur];
int pos = upper_bound(b + , b + + n, tofind) - b;
ans += get_sum(pos - );
//cout << tofind << " *****" << pos - 1 << endl;
}
// cout << cur << " " << ans << endl;
}
void dfs(int cur) {
calc(cur);
int pos = lower_bound(b + , b + + n, a[cur]) - b;
add(pos, );
for (int i = first[cur]; i; i = e[i].tonext) {
dfs(e[i].v);
}
add(pos, -);
}
void work() {
scanf("%d%I64d", &n, &k);
for (int i = ; i <= n; ++i) {
scanf("%I64d", &a[i]);
b[i] = a[i];
}
// for (int i = 1; i <= n; ++i) {
// cout << a[i] << " ";
// }
// cout << endl;
sort(b + , b + + n);
// for (int i = 1; i <= n; ++i) {
// cout << b[i] << " ";
// }
// cout << endl;
for (int i = ; i <= n - ; ++i) {
int u, v;
scanf("%d%d", &u, &v);
addedge(u, v);
in[v] = ;
}
int root = -inf;
for (int i = ; i <= n; ++i) {
if (in[i] == ) {
root = i;
break;
}
}
ans = ;
dfs(root);
// cout << ans << endl;
printf("%I64d\n", ans);
return ;
}
int main () {
#ifdef LOCAL
freopen("data.txt","r",stdin);
#endif
int t;
scanf("%d", &t);
while (t--) {
work();
num = ;
memset(in, , sizeof in);
memset(c, , sizeof c);
memset(first, , sizeof first);
}
return ;
}

HDU 5877 Weak Pair DFS + 树状数组 + 其实不用离散化的更多相关文章

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

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

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

    http://acm.hdu.edu.cn/showproblem.php?pid=5877 题意: 给出一棵树,每个顶点都有权值,现在要你找出满足要求的点对(u,v)数,u是v的祖先并且a[u]*a ...

  3. HDU 5877 Weak Pair(树状数组)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5877 [题目大意] 给出一棵带权有根树,询问有几对存在祖先关系的点对满足权值相乘小于等于k. [题 ...

  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 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Prob ...

  6. 树形DP+树状数组 HDU 5877 Weak Pair

    //树形DP+树状数组 HDU 5877 Weak Pair // 思路:用树状数组每次加k/a[i],每个节点ans+=Sum(a[i]) 表示每次加大于等于a[i]的值 // 这道题要离散化 #i ...

  7. Weak Pair (dfs+树状数组)

    Weak Pair (dfs+树状数组) 题意 这个题目是要求:一颗树上,有n个节点,给出每个节点的权值.另外给出一个值k,问有多少对节点满足: \(power[u]*power[v]<=k\) ...

  8. HDU 5877 Weak Pair(弱点对)

    HDU 5877 Weak Pair(弱点对) Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Jav ...

  9. hdu 5517 Triple(二维树状数组)

    Triple Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Sub ...

随机推荐

  1. Logstash 2.0.0 beta2 发布,开源日志管理

    Logstash 是一个应用程序日志.事件的传输.处理.管理和搜索的平台.你可以用它来统一对应用程序日志进行收集管理,提供 Web 接口用于查询和统计. Logstash 现在是 ElasticSea ...

  2. 上海-北京间通过Azure Storage的RA-GRS类型的存储账户进行快速复制

    Azure的Blob存储分成多种类型,目前主要有: 其中RA-GRS可以在上海-北京两个数据中心间同步数据.并且,在第二个数据中心可以只读的方式读取这个存储账户中的Blob内容. 虽然GRS采用的是准 ...

  3. nginx与apache 限制ip连接数和带宽方法

    今天有个人问我,nginx怎么限制ip连接数,突然想不起来了,年龄大了,脑子不怎么好使了.还要看一下配置才想起了.那个人又问我,你测试过的吗?一下子把我问蒙了,我真没测试过了,也不知道启作用了没有. ...

  4. java基础知识(9)---异常

    异 常: 异常:就是不正常.程序在运行时出现的不正常情况.其实就是程序中出现的问题.这个问题按照面向对象思想进行描述,并封装成了对象.因为问题的产生有产生的原因.有问题的名称.有问题的描述等多个属性信 ...

  5. mybatis---demo1--(缓存)----bai

    News-mapper.xml 配置: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ma ...

  6. Linux 文件名颜色

    在Linux中,文件的颜色都是有含义的.其中, 蓝色表示目录 绿色表示可执行文件 红色表示压缩文件 浅蓝色表示链接文件 灰色表示其它文件 红色闪烁表示链接的文件有问题了 黄色是设备文件,包括block ...

  7. ES6学习之函数扩展

    函数默认参数 function test(x = 1, y = 2) { return x + y } test(5, 6) test() 若默认参数在必须参数之前,要想取得默认参数,只有当传入的值为 ...

  8. shell批量创建用户随机密码

    批量创建用户随机密码企业面试题3:批量创建10个系统帐号usr01-usr10并设置密码(密码为随机8位字符串). #! /bin/bash . /etc/init.d/functions Path= ...

  9. Linux Shell 脚本提示:sleep: 无效的时间间隔"1s\r"

    问题:编写好的 Shell 脚本在 Linux 执行时提示报错:sleep: 无效的时间间隔"1s\r" : 原因:若再三确认脚本没有写错,可能是原脚本文件在 Win 下创建编写好 ...

  10. JSP相关背景

    -----------------siwuxie095                             Sun Microsystems             SUN 即 Stanford ...