学習フェーズ後の問題の概要リーグ

2019年12月1日〜2019年12月7日

「Luogu4556」Vaniは、日付を持っている - 雨の尾を

ポータル
ツリー+浴槽を考慮することができる明らかな違いは、このチェーンストランド上の点の位置の番号1は、バレルに対応してマークされるたびに更新され、
そして最終的にはタブの位置は、答えとして、各点の最大の非ゼロ値を取ります私たちすることができます、すべての出力は0、0にある場合はその時の複雑さとスペースの複雑です\(O(nm)を\)
この1つの最適化アルゴリズムを考える:
私たちの代わりにバレルの重みセグメントツリーの使用を考慮し
、我々は考えることができますチェーンを更新するための木のクロスの方法、それは範囲区間差分ログ・セグメント、各セグメントのツリーになり
、我々は従うことができますので、我々は、低深さの側に正のマークをプレイしている、ということに注意することが重要\(\ {テキストDFS} \ ) の順序演算子は答える
少し証拠を:

  • 現在のポイントへの貢献を求めてはいけない、これは明らかに影響はありません
  • お問い合わせの現在のポイントへの貢献は、その寄与が戻ってマークされた頂点の重いチェーンを築くためにでなければならない、それは確かに光除去息子の重鎖の終わりになるでしょう

このようなアクションは、オフラインアルゴリズムのための答え統計的方法が開きますツリーラインように、限り、似てただろう
コード:

#include <cstdio>
#include <vector>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
using namespace std;
template < class T > inline void read(T& s) {
    s = 0; int f = 0; char c = getchar();
    while ('0' > c || c > '9') f |= c == '-', c = getchar();
    while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
    s = f ? -s : s;
}

const int _ = 1e5 + 5;

int tot, head[_], nxt[_ << 1], ver[_ << 1];
inline void Add_edge(int u, int v)
{ nxt[++tot] = head[u], head[u] = tot, ver[tot] = v; }

int n, m, ans[_]; vector < int > vec[_];
int dep[_], siz[_], son[_], fa[_];
int dfn[_], rev[_], top[_];
struct node { int mx, pos; } t[_ << 2];

inline int lc(int p) { return p << 1; }

inline int rc(int p) { return p << 1 | 1; }

inline void pushup(int p) {
    if (t[lc(p)].mx >= t[rc(p)].mx)
        t[p].mx = t[lc(p)].mx, t[p].pos = t[lc(p)].pos;
    else
        t[p].mx = t[rc(p)].mx, t[p].pos = t[rc(p)].pos;
}

inline void build(int p = 1, int l = 1, int r = 100000) {
    if (l == r) { t[p].mx = 0, t[p].pos = l; return ; }
    int mid = (l + r) >> 1;
    build(lc(p), l, mid), build(rc(p), mid + 1, r), pushup(p);
}

inline void update(int x, int v, int p = 1, int l = 1, int r = 100000) {
    if (l == r) { t[p].mx += v; return ; }
    int mid = (l + r) >> 1;
    if (x <= mid) update(x, v, lc(p), l, mid);
    else update(x, v, rc(p), mid + 1, r);
    pushup(p);
}

inline void uptRange(int x, int y, int z) {
    int fx = top[x], fy = top[y];
    while (fx != fy) {
        if (dep[fx] < dep[fy]) swap(x, y), swap(fx, fy);
        vec[dfn[fx]].push_back(z), vec[dfn[x] + 1].push_back(-z);
        x = fa[fx], fx = top[x];
    }
    if (dep[x] > dep[y]) swap(x, y);
    vec[dfn[x]].push_back(z), vec[dfn[y] + 1].push_back(-z);
}

inline void dfs(int u, int f) {
    siz[u] = 1, dep[u] = dep[f] + 1, fa[u] = f;
    for (rg int i = head[u]; i; i = nxt[i]) {
        int v = ver[i]; if (v == f) continue;
        dfs(v, u), siz[u] += siz[v];
        if (siz[v] > siz[son[u]]) son[u] = v;
    }
}

inline void dfs(int u, int f, int topf) {
    top[rev[dfn[u] = ++dfn[0]] = u] = topf;
    if (son[u]) dfs(son[u], u, topf);
    for (rg int i = head[u]; i; i = nxt[i]) {
        int v = ver[i]; if (v == f || v == son[u]) continue;
        dfs(v, u, v);
    }
}

int main() {
#ifndef ONLINE_JUDGE
    file("cpp");
#endif
    read(n), read(m);
    for (rg int u, v, i = 1; i < n; ++i)
        read(u), read(v), Add_edge(u, v), Add_edge(v, u);
    dfs(1, 0), dfs(1, 0, 1), build();
    for (rg int x, y, z; m--; ) read(x), read(y), read(z), uptRange(x, y, z);
    for (rg int i = 1; i <= n; ++i) {
        for (rg int j : vec[i]) if (j > 0) update(j, 1); else update(-j, -1);
        ans[rev[i]] = t[1].mx > 0 ? t[1].pos : 0;
    }
    for (rg int i = 1; i <= n; ++i) printf("%d\n", ans[i]);
    return 0;
}

おすすめ

転載: www.cnblogs.com/zsbzsb/p/11966045.html