S - Query on a tree HDU - 3804 线段树+dfs序

 
离散化+权值线段树

 题目大意:给你一棵树,让你求这棵树上询问的点到根节点直接最大小于等于val的长度。

这个题目和之前写的那个给你一棵树询问这棵树的这个节点到根节点之间的节点权重相乘小于等于k的对数非常像。

之前是不是就是放进去弹出来的操作,这个也是一样,之前用的是离散化逆序对的思想来求,这个开始没有想到。

然后自己写了一个很暴力的线段树,线段树要是没有一个连续的区间是有很高复杂度的。

所以要想办法把这个转化成一个连续的区间,这个和上面一样通过逆序对的思想也可以转化成一个连续的区间。

首先把这个数进行离散化,然后建树,最后就是dfs序+线段树。

我这么写要注意初始化,因为可能是在根节点1 的时候询问,这个就不会在后面被考虑到,所以输出这个数组要初始化为-1

然后我出了一个在query这里,id<<1,忘记了 |1,

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <math.h>
#include <iostream>
#include <algorithm>
#define debug(n) printf("%d\n",n)
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 100;
int n, out[maxn], b[maxn], len;
struct node {
    int v;
    int w;
    node(int v = 0, int w = 0) :v(v), w(w) {}
};
struct edge {
    int w;
    int id;
    edge(int w = 0, int id = 0) :w(w), id(id) {}
};
vector<node>G[maxn];
vector<edge>e[maxn];
int sum[maxn * 4], maxx[maxn * 4];

void push_up(int id) {
    sum[id] = sum[id << 1] + sum[id << 1 | 1];
    maxx[id] = max(maxx[id << 1], maxx[id << 1 | 1]);
    // printf("maxx[%d]=%d\n",id,maxx[id]);
}

void update(int id, int l, int r, int pos, int val) {
    // printf("id=%d l=%d r=%d pos=%d val=%d\n", id, l, r, pos, val);
    if (l == r) {
        sum[id] += val;
        if (sum[id]) maxx[id] = l;
        else maxx[id] = 0;
        return;
    }
    int mid = (l + r) >> 1;
    if (pos <= mid) update(id << 1, l, mid, pos, val);
    else update(id << 1 | 1, mid + 1, r, pos, val);
    push_up(id);
}

int query(int id, int l, int r, int x, int y) {
    if (x <= l && y >= r) return maxx[id];
    int mid = (l + r) >> 1;
    int ans = 0;
    // printf("id=%d x=%d y=%d\n",id,x,y);
    if (x <= mid) ans = max(ans, query(id << 1, l, mid, x, y));
    // cout<<x<<' '<<y<<endl;
    if (y > mid) ans = max(ans, query(id << 1 | 1, mid + 1, r, x, y));
    // printf("!!id=%d ans=%d x=%intd y=%intd mid=%d\n", id, ans,x,y,mid);

    return ans;
}

void dfs(int u, int pre) {
    for (int i = 0; i < G[u].size(); i++) {
        node now = G[u][i];
        if (now.v == pre) continue;
        int t = lower_bound(b + 1, b + 1 + len, now.w) - b;
        update(1, 1, len, t, 1);
        // printf("www now.v=%d t=%d\n",now.v,t);
        for (int j = 0; j < e[now.v].size(); j++) {
            edge x = e[now.v][j];
            int t1 = upper_bound(b + 1, b + 1 + len, x.w) - b - 1;
            int ans = 0;
            if (t1 <= 0) {
                //  cout<<x.id<<'!'<<endl;
                out[x.id] = -1;
            }
            else {
                // printf("t1=%d\n",t1);
                ans = query(1, 1, len, 1, t1);
                if (ans == 0) out[x.id] = -1;
                else out[x.id] = b[ans];
            }
        }
        dfs(now.v, u);
        update(1, 1, len, t, -1);
        // printf("qqq now.v=%d t=%d\n",now.v,t);
    }
}


int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &n);
        for (int i = 0; i <= n; i++) G[i].clear(), e[i].clear();
        for (int i = 1; i < n; i++) {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            G[u].push_back(node(v, w));
            G[v].push_back(node(u, w));
            b[i] = w;
        }
        sort(b + 1, b + n);
        len = unique(b + 1, b + n) - b - 1;
        memset(sum, 0, sizeof(sum));
        memset(maxx, 0, sizeof(maxx));
        int q;
        scanf("%d", &q);
        for (int i = 1; i <= q; i++) {
            int u, w;
            scanf("%d%d", &u, &w);
            e[u].push_back(edge(w, i));
        }
        memset(out, -1, sizeof(out));
        dfs(1, -1);
        for (int i = 1; i <= q; i++) printf("%d\n", out[i]);
    }
    return 0;
}
/*
 4
 5
1 2 2
1 3 4
2 4 6
2 5 8
2
3 4
2 2
 */
线段树+dfs序

 

posted @ 2019-07-29 14:23  EchoZQN  阅读(198)  评论(0编辑  收藏  举报