1. 程式人生 > >[bzoj2870]最長道路tree

[bzoj2870]最長道路tree

題目大意:給你一棵帶點權的樹,要你求出樹上一條鏈,使得這條鏈的長度乘上這條鏈上點權最小值最大

題解:點分,可以求出一個點向下每一條鏈上最小值以及路徑長度,對於一個鏈的端點,假設到這部分子樹的重心距離為$dep$,這條鏈上最小值為$min$,記錄每一個最小值的最長鏈的長度,可以用樹狀陣列維護最大值(這裡是求字尾最大值,所以一次的複雜度還是$O(\log_2n)$),更新答案就行了。

卡點:1.寫成了字首求最大值

  2.離散化去重後長度未更改,導致用$lower\_bound$時出鍋

 

C++ Code:

#include <cstdio>
#include <cctype>
#include <algorithm>

namespace std {
    struct istream {
#define M (1 << 26 | 3)
        char buf[M], *ch = buf - 1;
        int f;
        inline istream() {
#ifndef ONLINE_JUDGE
            freopen("input.txt", "r", stdin);
#endif
            fread(buf, 1, M, stdin);
        }
        inline istream& operator >> (int &x) {
            f = 1;
            while (isspace(*++ch));
            if (*ch == '-') f = -1, ch++;
            for (x = *ch & 15; isdigit(*++ch); ) x = x * 10 + (*ch & 15);
            return *this;
        }
#undef M
    } cin;
    struct ostream {
#define M (1 << 16 | 3)
        char buf[M], *ch = buf - 1;
        int w;
        inline ostream& operator << (int x) {
            if (!x) {
                *++ch = '0';
                return *this;
            }
            if (x < 0) *++ch = '-', x = -x;
            for (w = 1; w <= x; w *= 10);
            for (w /= 10; w; w /= 10) *++ch = (x / w) ^ 48, x %= w;
            return *this;
        }
        long long W;
        inline ostream& operator << (long long x) {
            if (!x) {
                *++ch = '0';
                return *this;
            }
            if (x < 0) *++ch = '-', x = -x;
            for (W = 1; W <= x; W *= 10);
            for (W /= 10; W; W /= 10) *++ch = (x / W) ^ 48, x %= W;
            return *this;
        }
        inline ostream& operator << (const char x) {*++ch = x; return *this;}
        inline ostream& operator << (const char *x) {
            while (*x) *this << *x++;
            return *this;
        }
        inline ~ostream() {
#ifndef ONLINE_JUDGE
            freopen("output.txt", "w", stdout);
#endif
            fwrite(buf, 1, ch - buf + 1, stdout);
        }
#undef M
    } cout;
}

#define maxn 50010
const int inf = 0x3f3f3f3f;
inline void getmax(int &a, int b) {if (a < b) a = b;}
inline void getmax(long long &a, int b) {if (a < b) a = b;}

int head[maxn], cnt;
struct Edge {
    int to, nxt;
} e[maxn << 1];
inline void addedge(int a, int b) {
    e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
    e[++cnt] = (Edge) {a, head[b]}; head[b] = cnt;
}

bool vis[maxn];
namespace Center_of_Gravity {
    int sz[maxn], nodenum;
    int MIN, root;
#define n nodenum
    void __getroot(int u, int fa = 0) {
        sz[u] = 1;
        int MAX = 0;
        for (int i = head[u]; i; i = e[i].nxt) {
            int v = e[i].to;
            if (v != fa && !vis[v]) {
                __getroot(v, u);
                sz[u] += sz[v];
                MAX = std::max(MAX, sz[v]);
            }
        }
        MAX = std::max(MAX, n - sz[u]);
        if (MAX < MIN) MIN = MAX, root = u;
    }
    int getroot(int u, int __nodenum = 0) {
        n = __nodenum ? __nodenum : sz[u];
        MIN = inf;
        __getroot(u);
        return root;
    }
#undef n
}
using Center_of_Gravity::getroot;

int n, tot;
namespace BIT {
    int Tr[maxn], res;
#define n tot
    inline void add(int p, const int num) {for (; p; p &= p - 1) getmax(Tr[p], num);}
    inline int ask(int p) {for (res = -inf; p <= n; p += p & -p) getmax(res, Tr[p]); return res;}
    inline void clear(int p) {for (; p; p &= p - 1) Tr[p] = -inf;}
#undef n
}

int w[maxn], v[maxn];
long long ans;

int top;
struct List {
    int tg, dep, min;
} S[maxn];

void calc() {
    for (int l = 1, r; l <= top; l = r + 1) {
        r = l;
        while (r < top && S[l].tg == S[r + 1].tg) r++;
        for (int i = l; i <= r; i++) {
            ans = std::max(ans, static_cast<long long> (BIT::ask(S[i].min) + S[i].dep + 1) * v[S[i].min]);
        }
        for (int i = l; i <= r; i++) BIT::add(S[i].min, S[i].dep);
    }
    for (int i = 1; i <= top; i++) BIT::clear(S[i].min);
}

void getlist(int u, int tg, int min, int dep = 1, int fa = 0) {
    min = std::min(min, w[u]);
    S[++top] = (List) {tg, dep, min};
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if (v != fa && !vis[v]) getlist(v, tg, min, dep + 1, u);
    }
}
void solve(int u) {
    vis[u] = true; top = 0;
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if (!vis[v]) getlist(v, v, w[u]);
    }
    calc();
    std::reverse(S + 1, S + top + 1);
    calc();
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if (!vis[v]) solve(getroot(v));
    }
}

int main() {
    std::cin >> n;
    for (int i = 1; i <= n; i++) {
        std::cin >> w[i];
        getmax(ans, v[i] = w[i]);
    }
    tot = (std::sort(v + 1, v + n + 1), std::unique(v + 1, v + n + 1) - v - 1);
    for (int i = 1; i <= tot; i++) BIT::Tr[i] = -inf;
    for (int i = 1; i <= n; i++) {
        w[i] = std::lower_bound(v + 1, v + tot + 1, w[i]) - v;
    }
    for (int i = 1, a, b; i < n; i++) {
        std::cin >> a >> b;
        addedge(a, b);
    }
    solve(getroot(1, n));
    std::cout << ans << '\n';
    return 0;
}