「校内训练 2019-04-23」越野赛车问题 动态dp+树的直径

题目传送门

http://192.168.21.187/problem/1236

http://47.100.137.146/problem/1236

题解

题目中要求的显然是那个状态下的直径嘛。

所以这道题有一个非常简单的做法——线段树分治。

直接把每一条边按照 \(l, r\) 的区间放到线段树上进行分治,遍历的时候用并查集维护直径就可以了。

时间复杂度为 \(O(n\log^2n)\)。

很早以前就写了这个算法,代码附在了最后,不多讲了。

但是这道题还有一个方法——动态 DP。



线段树分治是给哪些不方便撤销不是按照栈的顺序撤销的操作的问题使用的,如果这个问题支持按照栈的顺序撤销修改,那么可以很好的使用线段树分治。

但是我们发现这个问题实际上不是栈的顺序的修改也可以做。也就是用动态 DP 维护树直径。

令 \(dp[x][0]\) 表示在 \(x\) 的子树子树中,从 \(x\) 上面那个边出发的最长链。(为什么是上面那个边:这样是否转移可以从 \(x\) 这里看出来,而不是需要在 \(x\) 的父亲那里转移的时候特判,方便 ddp)。

\(dp[x][1]\) 表示 \(x\) 的子树中的直径。

那么转移就是这样的(经典转移):
\[
dp[x][0] = \max_{y\in child_x} dp[y][0] + 1\\dp[x][1] = \max\{\max_{y\in child_x} dp[y][1], \max_{y1, y2 \in child_x} dp[y_1][0] + dp[y_2][0]\}
\]



设树剖完以后,\(x\) 的重儿子为 \(son_x\),轻儿子集合为 \(light_x\)。令 \(h[x][0] = \max\limits_{y\in light_x} dp[y][0]\),\(h[x][1] = \max\{\max\limits_{y\in light_x} dp[y][1], \max\limits_{y_1,y_2\in light_x} dp[y_1][0] + dp[y_2][0]\}\)。

这样上面的 dp 式子可以改写成:
\[
dp[x][0] = \max\{dp[son_x][0], h[x][0]\} + 1\\dp[y][0] = max\{ dp[son_x][1], h[x][1], dp[son_x][0] + h[x][0] \}
\]
于是转移矩阵就是(定义矩乘为求和后取 \(\max\)):
\[
\begin{bmatrix} 1 & -\infty & h[x][0] + 1 \\ h[x][0] & 0 & h[x][1] \\ -\infty & -\infty & 0 \end{bmatrix} \times \begin{bmatrix} dp[son_x][0] \\ dp[son_x][1] \\ 0 \end{bmatrix} = \begin{bmatrix} dp[x][0] \\ dp[x][1] \\ 0 \end{bmatrix}
\]
然后 ddp 就可以了。



关于 \(h\) 的维护:

我们维护两个可删除堆,\(q1[x]\) 记录所有的轻儿子 \(y\) 的 \(dp[y][0]\),\(q2[x]\) 记录所有的轻儿子 \(y\) 的 \(dp[y][1]\)。

\(h[x][0]\):显然是取 \(q1[x]\) 里面最大的;

\(h[x][1]\):首先是 \(q2[x]\) 里面最大的,然后再看看 \(q1[x]\) 里面最大的两个数的和是不是更大。



时间复杂度还是 \(O(n\log^2 n)\)。貌似我写的这个 ddp 被线段树分治碾压,但是 thx 写的就碾压了线段树分治。(雾

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back

template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}

typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;

template<typename I> inline void read(I &x) {
    int f = 0, c;
    while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    x = c & 15;
    while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    f ? x = -x : 0;
}

#define lc o << 1
#define rc o << 1 | 1

const int N = 70000 + 7;
const int INF = 0x3f3f3f3f;

int n, m, dfc;
int dep[N], f[N], siz[N], son[N], dfn[N], pre[N], bot[N], top[N];
int w[N], ans[N];
std::vector<int> v[N];

struct Edge { int to, ne, l, r; } g[N << 1]; int head[N], tot;
inline void addedge(int x, int y, int l, int r) { g[++tot].to = y, g[tot].l = l, g[tot].r = r, g[tot].ne = head[x], head[x] = tot; }
inline void adde(int x, int y, int l, int r) { addedge(x, y, l, r), addedge(y, x, l, r); }

struct Heap {
    std::priority_queue<int> q, p;
    inline void sync() { while (!q.empty() && !p.empty() && q.top() == p.top()) q.pop(), p.pop(); }
    inline void push(int x) { q.push(x); sync(); }
    inline void pop() { q.pop(); sync(); }
    inline void del(int x) { p.push(x), sync(); }
    inline int top() { sync(); return q.top(); }
    inline bool empty() { sync(); return q.empty(); }
    inline int size() { sync(); return q.size() - p.size(); }
} q1[N], q2[N];

inline int qtop(int x) {
    if (q1[x].empty()) return 0;
    else return q1[x].top();
}
inline int qtop2(int x) {
    int ans = q2[x].empty() ? 0 : q2[x].top(), sum = 0, tmp;
    if (q1[x].empty()) return ans;
    sum = q1[x].top(), q1[x].pop(), tmp = sum;
    if (!q1[x].empty()) sum += q1[x].top();
    q1[x].push(tmp);
    return std::max(sum, ans);
}// 记录一下这里的 sb 错误:最后返回的时候写成了 std::max(sum, tmp) 调了半个上午。

struct Matrix {
    int a[3][3];
    inline Matrix() { memset(a, 0, sizeof(a)); }
    inline Matrix operator * (const Matrix &b) {
        Matrix c;
        c.a[0][0] = std::max(std::max(a[0][0] + b.a[0][0], a[0][1] + b.a[1][0]), a[0][2] + b.a[2][0]);
        c.a[0][1] = std::max(std::max(a[0][0] + b.a[0][1], a[0][1] + b.a[1][1]), a[0][2] + b.a[2][1]);
        c.a[0][2] = std::max(std::max(a[0][0] + b.a[0][2], a[0][1] + b.a[1][2]), a[0][2] + b.a[2][2]);
        c.a[1][0] = std::max(std::max(a[1][0] + b.a[0][0], a[1][1] + b.a[1][0]), a[1][2] + b.a[2][0]);
        c.a[1][1] = std::max(std::max(a[1][0] + b.a[0][1], a[1][1] + b.a[1][1]), a[1][2] + b.a[2][1]);
        c.a[1][2] = std::max(std::max(a[1][0] + b.a[0][2], a[1][1] + b.a[1][2]), a[1][2] + b.a[2][2]);
        c.a[2][0] = std::max(std::max(a[2][0] + b.a[0][0], a[2][1] + b.a[1][0]), a[2][2] + b.a[2][0]);
        c.a[2][1] = std::max(std::max(a[2][0] + b.a[0][1], a[2][1] + b.a[1][1]), a[2][2] + b.a[2][1]);
        c.a[2][2] = std::max(std::max(a[2][0] + b.a[0][2], a[2][1] + b.a[1][2]), a[2][2] + b.a[2][2]);
        return c;
    }
} t[N << 2];

inline void dfs1(int x, int fa = 0) {
    dep[x] = dep[fa] + 1, f[x] = fa, siz[x] = 1;
    for fec(i, x, y) if (y != fa) dfs1(y, x), siz[x] += siz[y], siz[y] > siz[son[x]] && (son[x] = y);
}
inline void dfs2(int x, int pa) {
    top[x] = pa, dfn[x] = ++dfc, pre[dfc] = x;
    if (!son[x]) return (void)(bot[x] = x);
    dfs2(son[x], pa), bot[x] = bot[son[x]];
    for fec(i, x, y) if (y != f[x] && y != son[x]) dfs2(y, y);
}

inline void build(int o, int L, int R) {
    if (L == R) {
        int x = pre[L];
        if (w[x]) t[o].a[0][0] = 1, t[o].a[0][1] = -INF, t[o].a[0][2] = qtop(x) + 1;
        else t[o].a[0][0] = -INF, t[o].a[0][1] = -INF, t[o].a[0][2] = 0;
        t[o].a[1][0] = qtop(x), t[o].a[1][1] = 0, t[o].a[1][2] = qtop2(x);
        t[o].a[2][0] = -INF, t[o].a[2][1] = -INF, t[o].a[2][2] = 0;
        return;
    }
    int M = (L + R) >> 1;
    build(lc, L, M), build(rc, M + 1, R);
    t[o] = t[lc] * t[rc];
}
inline void qadd(int o, int L, int R, int x) {
    if (L == R) {
        int x = pre[L];
        if (w[x]) t[o].a[0][0] = 1, t[o].a[0][1] = -INF, t[o].a[0][2] = qtop(x) + 1;
        else t[o].a[0][0] = -INF, t[o].a[0][1] = -INF, t[o].a[0][2] = 0;
        t[o].a[1][0] = qtop(x), t[o].a[1][1] = 0, t[o].a[1][2] = qtop2(x);
        t[o].a[2][0] = -INF, t[o].a[2][1] = -INF, t[o].a[2][2] = 0;
        return;
    }
    int M = (L + R) >> 1;
    if (x <= M) qadd(lc, L, M, x);
    else qadd(rc, M + 1, R, x);
    t[o] = t[lc] * t[rc];
}
inline Matrix qsum(int o, int L, int R, int l, int r) {
    if (l <= L && R <= r) return t[o];
    int M = (L + R) >> 1;
    if (r <= M) return qsum(lc, L, M, l, r);
    if (l > M) return qsum(rc, M + 1, R, l, r);
    return qsum(lc, L, M, l, r) * qsum(rc, M + 1, R, l, r);
}

inline Matrix qry(int x) { return qsum(1, 1, n, dfn[x], dfn[bot[x]]) * Matrix(); }
inline void upd(int x, int k) {
    w[x] = k;
    while (top[x] != 1) {
        const Matrix &tmp1 = qry(top[x]);
        qadd(1, 1, n, dfn[x]);
        const Matrix &tmp2 = qry(top[x]);
        x = f[top[x]];
        q1[x].del(tmp1.a[0][0]), q1[x].push(tmp2.a[0][0]);
        q2[x].del(tmp1.a[1][0]), q2[x].push(tmp2.a[1][0]);
    }
    qadd(1, 1, n, dfn[x]);
}

inline void work() {
    dfs1(1), dfs2(1, 1), build(1, 1, n);
    for (int x = 1; x <= n; ++x)
        for fec(i, x, y) if (f[x] == y) v[g[i].l].pb(x), v[g[i].r].pb(-x);
    for (int i = 1; i <= n; ++i) {
        for (int x : v[i]) if (x > 0) upd(x, 1);
        ans[i] = qry(1).a[1][0];
        for (int x : v[i]) if (x < 0) upd(-x, 0);
    }
    int x;
    while (m--) read(x), printf("%d\n", ans[x]);
}

inline void init() {
    read(n), read(m);
    int x, y, l, r;
    for (int i = 1; i < n; ++i) read(x), read(y), read(l), read(r), adde(x, y, l, r);
}

int main() {
#ifdef hzhkk
    freopen("hkk.in", "r", stdin);
#else
    File(racing);
#endif
    init();
    work();
    fclose(stdin), fclose(stdout);
    return 0;
}


附录:线段树分治的做法以及每一个部分分的写法:

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back

template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}

typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;

template<typename I>
inline void read(I &x) {
    int f = 0, c;
    while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    x = c & 15;
    while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    f ? x = -x : 0;
}

const int N = 70000 + 7;

int n, m, flag_l1, flag_lian;
int _ask[N];

struct Edge {int to, ne, l, r;} g[N << 1]; int head[N], tot;
inline void addedge(int x, int y, int l, int r) {g[++tot].to = y; g[tot].l = l; g[tot].r = r; g[tot].ne = head[x]; head[x] = tot;}
inline void adde(int x, int y, int l, int r) {addedge(x, y, l, r); addedge(y, x, l, r);}

namespace Task1 {
    int v, ans;

    inline void dfs(int x, int dep = 0, int fa = 0) {
        smax(ans, dep);
        for fec(i, x, y) if (y != fa) {
            if (v < g[i].l || v > g[i].r) continue;
            dfs(y, dep + 1, x);
        }
    }

    inline void work() {
        for (int i = 1; i <= m; ++i) {
            v = _ask[i]; ans = 0;
            for (int j = 1; j <= n; ++j) dfs(j);
            printf("%d\n", ans);
        }
    }
}

namespace Task2 {
    int ans[N], w[N];

    std::set<pii> s;
    std::vector<int> wph[N];

    inline void work() {
        for (int i = 1; i < n; ++i)
            for fec(j, i, y) if (y == i + 1) w[i] = g[j].r;
        for (int i = 1; i < n; ++i) wph[w[i]].pb(i);
        for (int i = 1; i <= n; ++i) s.insert(pii(i, i));
        for (int i = n; i; --i) {
            ans[i] = ans[i + 1];
            if (wph[i].empty()) continue;
            for (auto j : wph[i]) {
                auto p = s.upper_bound(pii(j, n)), q = p;
                --q;
                smax(ans[i], p->se - q->fi);
                pii neww(q->fi, p->se);
                s.erase(p), s.erase(q);
                s.insert(neww);
            }
        }
        for (int i = 1; i <= m; ++i) printf("%d\n", ans[_ask[i]]);
    }
}

namespace Task3 {
    int ans[N], w[N], v[N];

    std::set<pii> s;
    std::vector<int> wph[N], thx[N];

    struct Heap {
        std::priority_queue<int> q, p;
        inline void sync() {while (!q.empty() && !p.empty() && q.top() == p.top()) q.pop(), p.pop();}
        inline void push(int x) {q.push(x), sync();}
        inline void del(int x) {p.push(x), sync();}
        inline int top() {sync(); return q.top();}
        inline bool empty() {sync(); return q.empty();}
    } yql;

    inline void work() {
        for (int i = 1; i < n; ++i)
            for fec(j, i, y) if (y == i + 1) w[i] = g[j].r, v[i] = g[j].l;
        for (int i = 1; i < n; ++i) wph[w[i]].pb(i);
        for (int i = 1; i < n; ++i) thx[v[i]].pb(i);
        for (int i = 1; i <= n; ++i) s.insert(pii(i, i)), yql.push(0);
        for (int i = n; i; --i) {
            for (auto j : wph[i]) {
                auto p = s.upper_bound(pii(j, n)), q = p;
                --q;
                pii neww(q->fi, p->se);
                yql.del(q->se - q->fi), yql.del(p->se - p->fi);
                s.erase(p), s.erase(q);
                s.insert(neww);
                yql.push(neww.se - neww.fi);
            }
            ans[i] = yql.top();
            // dbg("i = %d, ans[i] = %d\n", i, ans[i]);
            for (auto j : thx[i]) {
                // dbg("-----orz: ----- i = %d, j = %d\n", i, j);
                auto p = s.upper_bound(pii(j, n));
                --p;
                pii new1(p->fi, j), new2(j + 1, p->se);
                yql.del(p->se - p->fi);
                s.erase(p);
                yql.push(new1.se - new1.fi), yql.push(new2.se - new2.fi);
                s.insert(new1), s.insert(new2);
            }
        }
        for (int i = 1; i <= m; ++i) printf("%d\n", ans[_ask[i]]);
    }
}

namespace Task4 {
    #define lc o << 1
    #define rc o << 1 | 1

    inline int dist(int, int);

    int dfc;
    int dfn[N], dep[N], siz[N], son[N], f[N], top[N];
    int fa[N], mxd[N], ans[N];
    struct wph {
        int x, y, len;
        inline wph() {len = 0;}
        inline wph(int x, int y) : x(x), y(y) {len = dist(x, y);}
        inline bool operator < (const wph &a) const {return len < a.len;}
    } val[N];

    inline wph merge(wph, wph);

    inline int find(int x) {return fa[x] == x ? x : find(fa[x]);}
    inline void merge(int x, int y) {
        x = find(x), y = find(y);
        if (mxd[x] < mxd[y]) std::swap(x, y);
        fa[y] = x; val[x] = merge(val[x], val[y]);
        smax(mxd[x], mxd[y] + 1);
    }

    inline void dfs1(int x, int fa = 0) {
        dep[x] = dep[fa] + 1; f[x] = fa; siz[x] = 1;
        for fec(i, x, y) if (y != fa) dfs1(y, x), siz[x] += siz[y], siz[y] > siz[son[x]] && (son[x] = y);
    }
    inline void dfs2(int x, int pa) {
        top[x] = pa; dfn[x] = ++dfc;
        if (!son[x]) return; dfs2(son[x], pa);
        for fec(i, x, y) if (y != f[x] && y != son[x]) dfs2(y, y);
    }
    inline int LCA(int x, int y) {
        while (top[x] != top[y]) dep[top[x]] > dep[top[y]] ? x = f[top[x]] : y = f[top[y]];
        return dep[x] < dep[y] ? x : y;
    }
    inline int dist(int x, int y) {return dep[x] + dep[y] - (dep[LCA(x, y)] << 1);}

    std::vector<pii> t[N << 2], rem[N << 2];
    std::vector<wph> remx[N << 2], remy[N << 2];
    inline void qadd(int o, int L, int R, int l, int r, pii k) {
        if (l <= L && R <= r) return t[o].pb(k);
        int M = (L + R) >> 1;
        if (l <= M) qadd(lc, L, M, l, r, k);
        if (r > M) qadd(rc, M + 1, R, l, r, k);
    }

    inline wph merge(wph a, wph b) {
        wph ans = std::max(a, b);
        smax(ans, wph(a.x, b.x));
        smax(ans, wph(a.x, b.y));
        smax(ans, wph(a.y, b.x));
        smax(ans, wph(a.y, b.y));
        return ans;
    }

    inline void build() {
        for (int i = 1; i <= tot; i += 2) {
            int x = g[i].to, y = g[i + 1].to, l = g[i].l, r = g[i].r;
            qadd(1, 1, n, l, r, pii(x, y));
        }
    }

    inline void solve(int o, int L, int R, int ansv) {
        int len = t[o].size();
        for (auto i : t[o]) {
            int x = i.fi, y = i.se;
            rem[o].pb(pii(x = find(x), y = find(y)));
            remx[o].pb(val[x]), remy[o].pb(val[y]);
            merge(x, y); smax(ansv, std::max(val[x].len, val[y].len));
        }
        if (L == R) ans[L] = ansv;
        else {
            int M = (L + R) >> 1;
            solve(lc, L, M, ansv), solve(rc, M + 1, R, ansv);
        }
        for (int ii = len - 1; ~ii; --ii) {
            auto i = t[o][ii];
            int x  = i.fi, y = i.se;
            x = rem[o][ii].fi, y = rem[o][ii].se; rem[o].pop_back();
            fa[x] = x, fa[y] = y;
            val[x] = remx[o][ii], val[y] = remy[o][ii];
            remx[o].pop_back(), remy[o].pop_back();
        }
    }

    inline void ycl() {
        for (int i = 1; i <= n; ++i) {
            fa[i] = i;
            val[i] = wph(i, i);
        }
    }

    inline void work() {
        build();
        dfs1(1), dfs2(1, 1);
        ycl();
        solve(1, 1, n, 0);
        for (int i = 1; i <= m; ++i) printf("%d\n", ans[_ask[i]]);
    }
}

inline void init() {
    int u, v, l, r;
    read(n), read(m);
    flag_l1 = flag_lian = 1;
    for (int i = 1; i < n; ++i) {
        read(u), read(v), read(l), read(r);
        adde(u, v, l, r);
        flag_l1 = flag_l1 && l == 1;
        flag_lian = flag_lian && u == i && v == i + 1;
    }
    for (int i = 1; i <= m; ++i) read(_ask[i]);
}

int main() {
    #ifdef hzhkk
    freopen("hkk.in", "r", stdin);
    #else
    File(racing);
    #endif
    init();
    if (flag_l1 && flag_lian) Task2::work();
    else if (flag_lian) Task3::work();
    else if (n <= 20 && m <= 20) Task1::work();
    else Task4::work();
    fclose(stdin), fclose(stdout);
    return 0;
}

原文地址:https://www.cnblogs.com/hankeke/p/hzoj1236.html

时间: 2024-08-06 00:57:53

「校内训练 2019-04-23」越野赛车问题 动态dp+树的直径的相关文章

「日常训练与知识学习」树的分块(王室联邦,HYSBZ-1086)

题意与分析 这题的题意就是树分块,更具体的看题目(中文题). 学习这一题是为了树的分块,为树上莫队做铺垫. 参考1:https://blog.csdn.net/LJH_KOQI/article/details/52326103 参考2:https://blog.csdn.net/popoqqq/article/details/42772237 注意到题目要求某块区域所有的点到根的路径上的点都属于该区域.因此不能够暴力地去dfs,每找到\(B\)个分一块是不可取的,因为无法保证联通性(一颗子树的下

「美团 CodeM 初赛 Round B」送外卖2---------------状压dp

题目描述 一张 n 个点 m 条有向边的图上,有 q  个配送需求,需求的描述形式为 (si,ti,li,ri)( s_i , t_i , l_i , r_i )(si?,ti?,li?,ri?),即需要从点 si 送到 ti, 在时刻 li 之后(包括 lil_ili? )可以在 sis_isi? 领取货物,需要在时刻 ri 之前(包括 ri)送达 ti ,每个任务只需完成一次. 图上的每一条边均有边权,权值代表通过这条边消耗的时间.在时刻 000 有一个工作人员在点 1 上,求他最多能完成多

「美团 CodeM 初赛 Round B」景区路线规划 概率DP

题意 游乐园被描述成一张 n 个点,m 条边的无向图(无重边,无自环).每个点代表一个娱乐项目,第 i 个娱乐项目需要耗费 ci 分钟的时间,会让小 y 和妹子的开心度分别增加 h1i ,h2i ,他们俩初始的开心度都是 0 .每条边代表一条路,第 i 条边连接编号为 xi , yi 的两个娱乐项目,从 xi 走到 yi 或者从 yi 走到 xi 耗费的时间都是 ti 分钟.小 y 和妹子预计在游乐园里玩 k 分钟.最开始的时候,小 y 和妹子会等概率的随机选择一个娱乐项目开始玩,每玩完一个项目

「ZJOI2019」Minimax 搜索(动态dp)

Address loj3044 Solution 考虑对 \(k\in [l-1,r]\) 分别求出有多少个集合 \(S\) 满足 \(w(S)\le k\),记作 \(ans_k\). 先求出 \(1\) 的初始权值 \(W\). 记 \(val(x)\) 表示 \(x\) 的权值.枚举 \(k\),现在对于每个叶子 \(u\),如果 \(u\in S\),那么 \(val(u)\in [u-W,u+W]\),否则 \(val(u)=W\). 我们发现,把叶子节点的权值改成 \(W\) 肯定是

dtoj#4259. 越野赛车问题

题目描述: 小 $H$ 是一位优秀的越野赛车女选手.现在她准备在 $A$ 山上进行赛车训练. $A$ 山上一共有 $n$ 个广场,编号依次为 $1$ 到 $n$ ,这些广场之间通过 $n-1$条双向车道直接或间接地连接在一起.对于每条车道$i$ ,可以用四个正整数 $u_i,v_i,l_i,r_i$描述,表示车道连接广场 $u_i$ 和 $v_i$ ,其速度承受区间为$[l_i,r_i]$,即汽车必须以不小于$l_i$ 且不大于 $r_i$ 的速度经过车道$i$ . 小 $H$ 计划进行 $m$

「csp校内训练 2019-10-24」解题报告

「csp校内训练 2019-10-24」解题报告 T1.猴猴吃苹果 \(Description\) 猴猴最喜欢在树上玩耍,一天猴猴又跳上了一棵树,这棵树有 \(N \ (N \leq 50000)\) 个苹果,每个苹果有一个编号,分别为 \(0\) ~ \(N - 1\) 它们之间由 \(N-1\) 个树枝相连,猴猴可以从树枝的一端爬到树枝的另一端,所以猴猴可以从任意一个苹果的位置出发爬到任意猴猴想去的苹果的位置. 猴猴开始在编号为 \(K \ (K < N)\) 的苹果的位置,并且把这个苹果吃

「csp校内训练 2019-10-30」解题报告

「csp校内训练 2019-10-30」解题报告 T1.树 题目链接(逃) \(Description\): 现在有一棵树,共 \(N\) 个节点. 规定:根节点为 \(1\) 号节点,且每个节点有一个点权. 现在,有 \(M\) 个操作需要在树上完成,每次操作为下列三种之一: \(1 \ x \ a\):操作 \(1\),将节点 \(x\) 点权增加 \(a\). \(2 \ x \ a\):操作 \(2\),将以节点 \(x\) 为根的子树中所有点的权值增加 \(a\). \(3 \ x\)

「体能训练理论」之动力链 - 史努比的魔法书

引言 与其说体能训练是一种行为,不如说体能训练是一种程序.只要符合逻辑,就可以自由组合. 那么体能训练的逻辑是什么?我们将之总结为:动力链.功能性.金字塔. 动力链 如果说 五大运动素质(力量.速度.耐力.灵敏.柔韧)代表了体能的宏观表现,那么动力链理论则阐释了人体解剖结构在运动中的客观规律,这二者同为人体的本质属性. 动力链这一理论早在1875年就被提出过,当时的定义还很简单,就是指几个相邻的关节所组成的复杂动作单元.后来在不断地实践与研究中,动力链理论也不断的升级,越来越清晰,越来越客观,也

「七天自制PHP框架」第三天:PHP实现的设计模式

往期回顾:「七天自制PHP框架」第二天:模型与数据库,点击此处 原文地址:http://www.cnblogs.com/sweng/p/6624845.html,欢迎关注:编程老头 为什么要使用设计模式? 设计模式,我的理解是为了达到"可复用"这个目标,而设计的一套相互协作的类. 感兴趣的读者可以阅读<Design Patterns: Elements of Reusable Object-Oriented Software>,四位作者(Gang of Four)在书中列举