zoukankan      html  css  js  c++  java
  • 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的,树状数组即可。

    问题就是,数字太大了,这不适合树状数组,那么我们把每个数字离散成他们的下标即可,但其实这部的操作是不需要的,就是不需要用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
    ", 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;
    }
    View Code
  • 相关阅读:
    linux seqlock 锁
    linux 位操作
    linux 原子变量
    linux 读者/写者自旋锁
    linux自旋锁函数
    linux 自旋锁 API 简介
    linux Completions 机制
    linux 读者/写者旗标
    linux 在 scull 中使用旗标
    Linux 旗标实现
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/5862232.html
Copyright © 2011-2022 走看看