zoukankan      html  css  js  c++  java
  • Luogu 2495 [SDOI2011]消耗战

    BZOJ 2286

    传说中的虚树经典题。

    放上我觉得讲的很好的Luogu置顶题解。       传送门

    首先考虑一个暴力的$dp$,设$f_x$表示切断$x$的子树中的所有特殊点且保留$x$的最小代价和,$mn_x$表示$x$到根的路径上最小的一条边的权值。

    边界:搜一遍预处理$mn$,对于所有的特殊点$x$, $f_x = mn_x$,其他的点$y$,$f_y = 0$。

    转移也比较显然$f_x = sum_{y} min(mn_y, f_y)$   $y in son(x)$。

    这样子$n^2$的做法就拿到了40分。

    我们在$dp$的时候发现其实一次要用的点很少,最多就是所有的特殊点,$1$,还有一些特殊点的$lca$,那么我们可以直接把这些需要的点保留下来重新构造一颗新的树来$dp$,这样子会快很多。

    好像这个东西就叫虚树吧。

    对于一棵树,我们只要知道了它的欧拉序就可以知道这棵树到底是长什么样的,发现构造出来的这颗新的树上所有点的相对欧拉序都没有变化,而且使用欧拉序还有一个好处,那就是在插入$lca$的时候只要先按照欧拉序排一波序然后按顺序插入就好了,感觉这比很多网上的用栈维护这个$lca$的方法要好很多。

    按照所有点的欧拉序排序后模拟系统栈$dp$即可。

    时间复杂度似乎是$O(nlogn)$,并不会算。

    另外注意每次在弹栈的时候初始化一下就好了,我一开始用$memset$T了。

    Code:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    
    const int N = 2.5e5 + 5;
    const int Lg = 20;
    const ll inf = 1LL << 60;
    
    int n, qn, tot = 0, head[N], top = 0, sta[N << 2], a[N << 2];
    int fa[N][Lg], dep[N], dfsc = 0, in[N], out[N];
    ll mn[N], f[N];
    bool vis[N];
    
    struct Edge {
        int to, nxt;
        ll val;
    } e[N << 1];
    
    inline void add(int from, int to, ll val) {
        e[++tot].to = to;
        e[tot].val = val;
        e[tot].nxt = head[from];
        head[from] = tot;
    }
    
    template <typename T>
    inline void read(T &X) {
        X = 0; char ch = 0; T op = 1;
        for(; ch > '9' || ch < '0'; ch = getchar())
            if(ch == '-') op = -1;
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }
    
    bool cmp(int x, int y) {
        int dfx = x > 0 ? in[x] : out[-x];
        int dfy = y > 0 ? in[y] : out[-y];
        return dfx < dfy;
    }
    
    inline ll min(ll x, ll y) {
        return x > y ? y : x;
    }
    
    void dfs(int x, int fat, int depth, ll nowMn) {
        fa[x][0] = fat, dep[x] = depth, mn[x] = nowMn;
        in[x] = ++dfsc;
        for(int i = 1; i <= 18; i++)
            fa[x][i] = fa[fa[x][i - 1]][i - 1];
        for(int i = head[x]; i; i = e[i].nxt) {
            int y = e[i].to;
            if(y == fat) continue;
            dfs(y, x, depth + 1, min(nowMn, e[i].val));
        }
        out[x] = ++dfsc;
    }
    
    inline void swap(int &x, int &y) {
        int t = x; x = y; y = t;
    }
    
    inline int getLca(int x, int y) {
        if(dep[x] < dep[y]) swap(x, y);
        for(int i = 18; i >= 0; i--)
            if(dep[fa[x][i]] >= dep[y])
                x = fa[x][i];
        if(x == y) return x;
        for(int i = 18; i >= 0; i--)
            if(fa[x][i] != fa[y][i])
                x = fa[x][i], y = fa[y][i];
        return fa[x][0];
    }
    
    void solve() {
        int K, cnt; read(K);
        for(int i = 1; i <= K; i++) {
            read(a[i]);
            vis[a[i]] = 1, f[a[i]] = mn[a[i]];
        }
        
        cnt = K;
        sort(a + 1, a + 1 + cnt, cmp);
        for(int i = 1; i < cnt; i++) {
            int now = getLca(a[i], a[i + 1]);
            if(!vis[now]) {
                vis[now] = 1;
                a[++cnt] = now;
            }
        }
        
        for(int cur = cnt, i = 1; i <= cur; i++)
            a[++cnt] = -a[i];
        if(!vis[1]) a[++cnt] = 1, a[++cnt] = -1;
         
        sort(a + 1, a + 1 + cnt, cmp);
        top = 0;
        for(int i = 1; i <= cnt; i++) {
            if(a[i] > 0) sta[++top] = a[i];
            else {
                int x = sta[top--];
                if(x == 1) printf("%lld
    ", f[x]);
                else {
                    int y = sta[top];
                    f[y] += min(mn[x], f[x]);            
                }
                f[x] = 0LL, vis[x] = 0;
            }
        }
    }
    
    int main() {
        read(n);
        for(int x, y, i = 1; i < n; i++) {
            read(x), read(y);
            ll v; read(v);
            add(x, y, v), add(y, x, v);
        }    
        
        dfs(1, 0, 1, inf);
        for(read(qn); qn--; ) solve();
        
        return 0;
    }
    View Code
  • 相关阅读:
    设计模式学习总结系列应用实例
    【研究课题】高校特殊学生的发现及培养机制研究
    Linux下Oracle11G RAC报错:在安装oracle软件时报file not found一例
    python pro practice
    openstack python sdk list tenants get token get servers
    openstack api
    python
    git for windows
    openstack api users list get token get servers
    linux 流量监控
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9698976.html
Copyright © 2011-2022 走看看