• Codeforces 1179D Fedor Runs for President dp + 斜率优化


    Fedor Runs for President

    考虑 一棵基环树, 只有对应在基环上同一点的点对是一条路径。我们目标是使一条路经的数目尽可能少。

    dp[ u ] 表示从下延伸上来的一条最优链。 但是在当前这个点 u 作为交汇点的时候, 需要从它儿子中选两个

    合起来得到最优值, 这个需要用斜率去优化, 但是好像被我用个很蠢的贪心水过去了。。  明天再补个斜率

    优化的把。。

    #include<bits/stdc++.h>
    #define LL long long
    #define LD long double
    #define ull unsigned long long
    #define fi first
    #define se second
    #define mk make_pair
    #define PLL pair<LL, LL>
    #define PLI pair<LL, int>
    #define PII pair<int, int>
    #define SZ(x) ((int)x.size())
    #define ALL(x) (x).begin(), (x).end()
    #define fio ios::sync_with_stdio(false); cin.tie(0);
    
    using namespace std;
    
    const int N = 5e5 + 7;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int mod = 1e9 + 7;
    const double eps = 1e-8;
    const double PI = acos(-1);
    
    template<class T, class S> inline void add(T &a, S b) {a += b; if(a >= mod) a -= mod;}
    template<class T, class S> inline void sub(T &a, S b) {a -= b; if(a < 0) a += mod;}
    template<class T, class S> inline bool chkmax(T &a, S b) {return a < b ? a = b, true : false;}
    template<class T, class S> inline bool chkmin(T &a, S b) {return a > b ? a = b, true : false;}
    
    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    
    int n;
    vector<int> G[N];
    
    LL dp[N], sz[N];
    LL mn, ans;
    
    void dfs(int u, int fa) {
        dp[u] = INF;
        sz[u] = 1;
        if(SZ(G[u]) == 1 && fa) {
            dp[u] = 0;
            return;
        }
        PLL mn1 = mk(INF, INF);
        PLL mn2 = mk(INF, INF);
        for(auto &v : G[u]) {
            if(v == fa) continue;
            dfs(v, u);
            sz[u] += sz[v];
            if(mk(-sz[v], dp[v]) <= mn1) mn2 = mn1, mn1 = mk(-sz[v], dp[v]);
            else if(mk(-sz[v], dp[v]) < mn2) mn2 = mk(-sz[v], dp[v]);
            chkmin(mn, dp[v] + 1LL * (n - sz[v]) * (n - sz[v] - 1) / 2);
        }
        for(auto &v : G[u]) {
            if(v == fa) continue;
            LL tmp = dp[v] + (sz[u] - sz[v]) * (sz[u] - sz[v] - 1) / 2;
            chkmin(dp[u], tmp);
        }
        mn1.fi = -mn1.fi;
        mn2.fi = -mn2.fi;
        if(abs(mn1.fi) < INF && abs(mn2.fi) < INF) {
            chkmin(mn, mn1.se + mn2.se + 1LL * (n - mn1.fi - mn2.fi) * (n - mn1.fi - mn2.fi - 1) / 2);
        }
    }
    
    int main() {
        scanf("%d", &n);
        for(int i = 1; i < n; i++) {
            int u, v; scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        ans = 1LL * n * (n - 1);
        mn = 1LL * n * (n - 1) / 2;
        dfs(1, 0);
        printf("%lld
    ", ans - mn);
        return 0;
    }
    
    /*
    */

    维护直线板子

    #include<bits/stdc++.h>
    #define LL long long
    #define LD long double
    #define ull unsigned long long
    #define fi first
    #define se second
    #define mk make_pair
    #define PLL pair<LL, LL>
    #define PLI pair<LL, int>
    #define PII pair<int, int>
    #define SZ(x) ((int)x.size())
    #define ALL(x) (x).begin(), (x).end()
    #define fio ios::sync_with_stdio(false); cin.tie(0);
    
    using namespace std;
    
    const int N = 5e5 + 7;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int mod = 1e9 + 7;
    const double eps = 1e-8;
    const double PI = acos(-1);
    
    template<class T, class S> inline void add(T &a, S b) {a += b; if(a >= mod) a -= mod;}
    template<class T, class S> inline void sub(T &a, S b) {a -= b; if(a < 0) a += mod;}
    template<class T, class S> inline bool chkmax(T &a, S b) {return a < b ? a = b, true : false;}
    template<class T, class S> inline bool chkmin(T &a, S b) {return a > b ? a = b, true : false;}
    
    
    
    namespace LC {
    /**
     * Description: Container where you can add lines of the form kx+m, and query maximum values at points x.
     * Time: O(log N)
     */
    
    struct Line {
        mutable LL k, m, p;
        bool operator < (const Line& o) const { return k < o.k; }
        bool operator < (LL x) const { return p < x; }
    };
    
    struct LineContainer : multiset<Line, less<>> {
        // (for doubles, use inf = 1/.0, div(a,b) = a/b)
        const LL inf = LLONG_MAX;
        LL div(LL a, LL b) { // floored division
            return a / b - ((a ^ b) < 0 && a % b);
        }
        bool isect(iterator x, iterator y) {
            if (y == end()) { x->p = inf; return false; }
            if (x->k == y->k) x->p = x->m > y->m ? inf : -inf;
            else x->p = div(y->m - x->m, x->k - y->k);
            return x->p >= y->p;
        }
        void add(LL k, LL m) {
            auto z = insert({k, m, 0}), y = z++, x = y;
            while (isect(y, z)) z = erase(z);
            if (x != begin() && isect(--x, y)) isect(x, y = erase(y));
            while ((y = x) != begin() && (--x)->p >= y->p)
                isect(x, erase(y));
        }
        LL query(LL x) {
            assert(!empty());
            auto l = *lower_bound(x);
            return l.k * x + l.m;
        }
    };
    }
    
    int n;
    vector<int> G[N];
    
    LL dp[N], sz[N];
    LL mn, ans;
    
    LL c2(LL n) {
        return n * (n - 1) / 2;
    }
    
    void dfs(int u, int fa) {
        sz[u] = 1;
        for(auto &v : G[u]) {
            if(v == fa) continue;
            dfs(v, u);
            sz[u] += sz[v];
        }
    
        dp[u] = c2(sz[u]);
        for(auto &v : G[u]) {
            if(v == fa) continue;
            chkmin(dp[u], dp[v] + c2(sz[u] - sz[v]));
        }
    
    
        for(auto &v : G[u]) {
            if(v == fa) continue;
            chkmin(mn, dp[v] + c2(n - sz[v]));
        }
    
        LC::LineContainer cont;
        for(auto &v : G[u]) {
            if(v == fa) continue;
            if(!cont.empty()) {
                chkmin(mn, dp[v] + c2(n) - n * sz[v] + c2(sz[v] + 1) - cont.query(sz[v]));
            }
            cont.add(-sz[v], -(dp[v] - n * sz[v] + c2(sz[v] + 1)));
        }
    }
    
    
    /*
    dp[u] + dp[v] + (n - sz[u] - sz[v]) * (n - sz[u] - sz[v] - 1) / 2
    dp[u] + dp[v] + c2(n) - n * sz[u] - n * sz[v] + (sz[u] * sz[u] + sz[u] * sz[v] + sz[u] + sz[u] * sz[v] + sz[v] * sz[v] + sz[v]) / 2
    dp[u] + dp[v] + c2(n) - n * sz[u] - n * sz[v] + c2(sz[u] + 1) + c2(sz[v] + 1) + sz[u] * sz[v]
    */
    int main() {
        scanf("%d", &n);
        for(int i = 1; i < n; i++) {
            int u, v; scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        ans = 1LL * n * (n - 1);
        mn = 1LL * n * (n - 1) / 2;
        dfs(1, 0);
        printf("%lld
    ", ans - mn);
        return 0;
    }
    
    /*
    */
  • 相关阅读:
    googleMapReduce
    leveldb0
    大端模式和小端模式
    信号
    js中判断对象类型的几种方法
    js DOM之基础详解
    JavaScript作用域与闭包总结
    SCRIPT438: 对象不支持“trim”属性或方法
    JS合并多个数组去重算法
    js的 break 和 continue 计算问题
  • 原文地址:https://www.cnblogs.com/CJLHY/p/11102840.html
Copyright © 2020-2023  润新知