在线更新问题 HDU5877 线段树

题目大意:给你一棵树,有n-1条边,每条边都有方向,每个顶点有权值,给出weak pair的定义是val[u]*val[v] <=k,u是v的祖先,问有多少对这样的顶点

思路:创建线段树,通过dfs动态创建,每次都不断更新。因为我们只能是根节点开始往下的,所以我们遍历到兄弟节点的之前要把其他的兄弟节点的信息给删除掉。(这就和用vis标记一样的,一会儿变为true,一会儿变为false)

不过我很奇怪,为啥我的代码没有吧k/a[i]放进去就迷之RE了

当然,这道题也可以用主席树做,也可以用treap做

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
const int maxn = 4e5 + 5;
LL a[maxn], b[maxn], d[maxn], tree[maxn * 4];
LL n, m, k, lenb, ans;
vector<int> E[maxn];

int query(int o, int l, int r, int ql, int qr){
    if (l >= ql && r <= qr){
        return tree[o];
    }
    int cnt = 0;
    int mid = (l + r) / 2;
    if (ql <= mid) cnt += query(o << 1, l, mid, ql, qr);
    if (qr > mid) cnt += query(o << 1 | 1, mid + 1, r, ql, qr);
    return cnt;
}

inline void push_up(int o){
    int lb = o << 1, rb = o << 1 | 1;
    tree[o] = tree[lb] + tree[rb];
}

void update (int o, int l, int r, int pos, int val){
    if (l == r && l == pos) {
        tree[o] += val;
        return ;
    }
    int mid = (l + r) / 2;
    if (pos <= mid) update(o << 1, l, mid, pos, val);
    if (pos > mid) update(o << 1 | 1, mid + 1, r, pos, val);
    push_up(o);
}

void dfs(int u){
    int pos = lower_bound(b + 1, b + 1 + m, a[u]) - b;
    int posk = lower_bound(b + 1, b + 1 + m, k / a[u]) - b;
    ans += query(1, 1, lenb, 1, posk);
    int len = E[u].size();
    update(1, 1, lenb, pos, 1);
    for (int i = 0; i < len; i++){
        int v = E[u][i];
        dfs(v);
    }
    update(1, 1, lenb, pos, -1);
}

int main(){
    int t; cin >> t;
    while (t--){
        memset(d, 0, sizeof(d));
        memset(tree, 0, sizeof(tree));
        scanf("%I64d%I64d", &n, &k);
        for (int i = 1; i <= n; i++){
            scanf("%I64d", a + i);
            b[i] = a[i];
            E[i].clear();
        }
        m = n;
        for (int i = 1; i <= n; i++) b[++m] = k / a[i];
        
        sort(b + 1, b + 1 + m);
        lenb = unique(b + 1, b + 1 + m) - b - 1;///序列长度1~n
        ///printf("lenb = %d
", lenb);
        for (int i = 1; i <= n - 1; i++){
            int u, v; scanf("%d%d", &u, &v);
            E[u].pb(v);
            d[v]++;
        }
        ans = 0;
        for (int i = 1; i <= n; i++){
            if (d[i] == 0){
                dfs(i);
                break;
            }
        }
        printf("%I64d
", ans);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/heimao5027/p/5863152.html