标签:
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 + 20; 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 <= 0) return; while (pos<=n) { // c[pos] += val; pos += lowbit(pos); } return ; } int get_sum (int pos) { //???1--pos??? if (pos <= 0) return 0; int ans = 0; while (pos) { ans += c[pos]; pos -= lowbit(pos); } return ans; } void calc(int cur) { if (a[cur] == 0) { ans += get_sum(n); } else { LL tofind = k / a[cur]; int pos = upper_bound(b + 1, b + 1 + n, tofind) - b; ans += get_sum(pos - 1); //cout << tofind << " *****" << pos - 1 << endl; } // cout << cur << " " << ans << endl; } void dfs(int cur) { calc(cur); int pos = lower_bound(b + 1, b + 1 + n, a[cur]) - b; add(pos, 1); for (int i = first[cur]; i; i = e[i].tonext) { dfs(e[i].v); } add(pos, -1); } void work() { scanf("%d%I64d", &n, &k); for (int i = 1; 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 + 1, b + 1 + n); // for (int i = 1; i <= n; ++i) { // cout << b[i] << " "; // } // cout << endl; for (int i = 1; i <= n - 1; ++i) { int u, v; scanf("%d%d", &u, &v); addedge(u, v); in[v] = 1; } int root = -inf; for (int i = 1; i <= n; ++i) { if (in[i] == 0) { root = i; break; } } ans = 0; 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 = 0; memset(in, 0, sizeof in); memset(c, 0, sizeof c); memset(first, 0, sizeof first); } return 0; }
HDU 5877 Weak Pair DFS + 树状数组 + 其实不用离散化
标签:
原文地址:http://www.cnblogs.com/liuweimingcprogram/p/5862232.html