樹鏈剖分+線段樹 HDOJ 5029 Relief grain(分配糧食)

 

題目連接php

題意:c++

  分糧食我就當成塗色了。有n個點的一棵樹,在a到b的路上都塗上c顏色,顏色可重複疊加,問最後每個點的最大顏色數量的顏色類型。ui

思路:blog

  首先這題的輸出是每個點最後的狀況,考慮離線作法。簡化版問題:在一條線段上塗色,問每一個點的最後的狀況,假設在[a, b]區間塗色,那麼在開始的位置a標記開始塗色,在結束的位置標記結束塗色,一棵動態的顏色樹,維護當前顏色數量最大的數量。那麼這題也能夠考慮這麼作,先對樹進行樹鏈剖分,而後按照剖分順序dfn來遍歷,提早讀入全部操做,在塗色的兩端標記,後面操做和簡化版同樣了。get

#include <bits/stdc++.h>

const int N = 1e5 + 5;

std::vector<int> edges[N];
int n, m;

//顏色樹
#define lson l, mid, o << 1
#define rson mid + 1, r, o << 1 | 1

int mx[N<<2];

void push_up(int o) {
    mx[o] = std::max (mx[o<<1], mx[o<<1|1]);
}

void build(int l, int r, int o) {
    mx[o] = 0;
    if (l == r) return ;
    int mid = l + r >> 1;
    build (lson);
    build (rson);
}

void updata(int p, int c, int l, int r, int o) {
    if (l == r) {
        mx[o] += c;
        return ;
    }
    int mid = l + r >> 1;
    if (p <= mid) updata (p, c, lson);
    else updata (p, c, rson);
    push_up (o);
}

int query(int l, int r, int o) {
    if (l == r) return l;
    int mid = l + r >> 1;
    if (mx[o<<1] == mx[o]) return query (lson);
    else return query (rson);
}

int sz[N], fa[N], dfn[N], belong[N];
int idx[N];
int tim;

void DFS2(int u, int chain) {
    dfn[u] = ++tim;
    idx[tim] = u;
    belong[u] = chain;
    int k = 0;
    for (auto v: edges[u]) {
        if (v == fa[u]) continue;
        if (sz[v] > sz[k]) k = v;
    }
    if (k) DFS2 (k, chain);
    for (auto v: edges[u]) {
        if (v == fa[u] || v == k) continue;
        DFS2 (v, v);
    }
}

void DFS(int u, int pa) {
    sz[u] = 1;
    fa[u] = pa;
    for (auto v: edges[u]) {
        if (v == pa) continue;
        DFS (v, u);
        sz[u] += sz[v];
    }
}

std::vector<int> add[N], sub[N];
int ans[N];

void mark(int a, int b, int c) {
    int p = belong[a], q = belong[b];
    while (p != q) {
        if (dfn[p] < dfn[q]) {
            std::swap (p, q);
            std::swap (a, b);
        }
        add[dfn[p]].push_back (c);
        sub[dfn[a]+1].push_back (c);  //son[a]
        a = fa[p];
        p = belong[a];
    }
    if (dfn[a] < dfn[b]) std::swap (a, b);
    add[dfn[b]].push_back (c);
    sub[dfn[a]+1].push_back (c);
}

void prepare() {
    sz[0] = 0;
    DFS (1, 0);
    tim = 0;
    DFS2 (1, 1);
}

int main() {
    while (scanf ("%d%d", &n, &m) == 2 && n + m) {
        for (int i=1; i<=n; ++i) {
            edges[i].clear ();
            add[i].clear ();
            sub[i].clear ();
        }
        for (int i=1; i<n; ++i) {
            int u, v;
            scanf ("%d%d", &u, &v);
            edges[u].push_back (v);
            edges[v].push_back (u);
        }

        prepare ();

        int maxc = 1;
        for (int i=1; i<=m; ++i) {
            int a, b, c;
            scanf ("%d%d%d", &a, &b, &c);
            mark (a, b, c);
            maxc = std::max (maxc, c);
        }
        
        build (1, maxc, 1);

        //dfn
        for (int i=1; i<=n; ++i) {
            for (int j=0; j<add[i].size (); ++j) {
                updata (add[i][j], 1, 1, maxc, 1);
            }
            for (int j=0; j<sub[i].size (); ++j) {
                updata (sub[i][j], -1, 1, maxc, 1);
            }
            ans[idx[i]] = mx[1] ? query (1, maxc, 1) : 0;
        }

        for (int i=1; i<=n; ++i) {
            printf ("%d\n", ans[i]);
        }
    }
    return 0;
}
相關文章
相關標籤/搜索