• Bzoj3672: [Noi2014]购票


    题面

    传送门

    Sol

    (f[i])表示(i)到根的最小代价
    (f[i])可以由(f[j])转移而来,要求(j)(i)的父亲,并且满足距离限制

    显然(DP)式可以斜率优化
    然而这是在树上,并且每次都要一个(i)往上的若干个点的凸包

    可以考虑维护区间凸包,可以用线段树
    或者(CDQ)分治

    (CDQ)分治的方法,其实是点分治,每次先解决重心到其祖先那一块
    然后考虑它们对其它子树的贡献,区间凸包可以转化为后缀凸包
    排序后每次在前面加入并查询即可

    # include <bits/stdc++.h>
    # define IL inline
    # define RG register
    # define Fill(a, b) memset(a, b, sizeof(a))
    using namespace std;
    typedef long long ll;
    
    IL ll Input(){
        RG ll x = 0, z = 1; RG char c = getchar();
        for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
        for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
        return x * z;
    }
    
    const int maxn(2e5 + 5);
    
    int n, first[maxn], cnt;
    int vis[maxn], size[maxn], mx[maxn], rt, sz, fa[maxn];
    int q1[maxn], q2[maxn], l1, r1, len, anc[maxn], num;
    ll deep[maxn], s[maxn], f[maxn], l[maxn], q[maxn], p[maxn];
    
    struct Edge{
        int to, next;
        ll w;
    } edge[maxn << 1];
    
    IL void Add(RG int u, RG int v, RG ll w){
        edge[cnt] = (Edge){v, first[u], w}, first[u] = cnt++;
    }
    
    IL void Dfs(RG int u, RG int ff){
        s[u] = deep[u] * p[u] + q[u], l[u] = deep[u] - l[u];
        for(RG int e = first[u]; e != -1; e = edge[e].next){
            RG int v = edge[e].to;
            if(v != ff){
                deep[v] = deep[u] + edge[e].w;
                fa[v] = u, Dfs(v, u);
            }
        }
    }
    
    IL void GetRoot(RG int u, RG int ff){
        size[u] = 1, mx[u] = 0;
        for(RG int e = first[u]; e != -1; e = edge[e].next){
            RG int v = edge[e].to;
            if(v != ff && !vis[v]){
                GetRoot(v, u);
                size[u] += size[v];
                mx[u] = max(mx[u], size[v]);
            }
        }
        mx[u] = max(mx[u], sz - size[u]);
        if(mx[u] < mx[rt]) rt = u;
    }
    
    IL void GetSon(RG int u, RG int ff){
        q2[++len] = u;
        for(RG int e = first[u]; e != -1; e = edge[e].next){
            RG int v = edge[e].to;
            if(!vis[v] && v != ff) GetSon(v, u);
        }
    }
    
    IL int Cmp(RG int x, RG int y){
        return l[x] > l[y];
    }
    
    IL double Slope(RG int x, RG int y){
        return 1.0 * (f[x] - f[y]) / (1.0 * (deep[x] - deep[y]));
    }
    
    IL void Solve(RG int last, RG int u){
        vis[u] = 1;
        for(RG int e = first[u]; e != -1; e = edge[e].next)
            if(edge[e].to == fa[u] && !vis[edge[e].to]){
                rt = 0, sz = size[edge[e].to];
                GetRoot(edge[e].to, u), Solve(last, rt);
            }
        num = len = 0, GetSon(u, fa[u]);
        for(RG int i = u; i != last; i = fa[i]) anc[++num] = fa[i];
        l1 = 0, r1 = -1, sort(q2 + 1, q2 + len + 1, Cmp);
        for(RG int i = 1, j = 1; i <= len; ++i){
            while(j <= num && deep[anc[j]] >= l[q2[i]]){
                while(l1 < r1 && Slope(q1[r1 - 1], q1[r1]) <= Slope(q1[r1 - 1], anc[j])) --r1;
                q1[++r1] = anc[j++];
            }
            if(l1 <= r1){
                RG int ql = l1 + 1, qr = r1, pos = l1;
                while(ql <= qr){
                    RG int mid = (ql + qr) >> 1;
                    if(Slope(q1[mid - 1], q1[mid]) > p[q2[i]]) pos = mid, ql = mid + 1;
                    else qr = mid - 1;
                }
                f[q2[i]] = min(f[q2[i]], f[q1[pos]] + s[q2[i]] - deep[q1[pos]] * p[q2[i]]);
            }
        }
        for(RG int e = first[u]; e != -1; e = edge[e].next)
            if(edge[e].to != fa[u] && !vis[edge[e].to]){
                rt = 0, sz = size[edge[e].to];
                GetRoot(edge[e].to, u), Solve(u, rt);
            }
    }
    
    int main(){
        n = Input(), Input();
        for(RG int i = 1; i <= n; ++i) first[i] = -1, f[i] = 1e18;
        mx[0] = n + 1, sz = n, f[1] = 0;
        for(RG int i = 2; i <= n; ++i){
            RG ll ff = Input(), w = Input();
            Add(ff, i, w), Add(i, ff, w);
            p[i] = Input(), q[i] = Input(), l[i] = Input();
        }
        Dfs(1, 0), GetRoot(1, 0), Solve(1, rt);
        for(RG int i = 2; i <= n; ++i) printf("%lld
    ", f[i]);
        return 0;
    }
    
  • 相关阅读:
    NSString、NSMutableString基本用法
    iOS开发之UITextField的使用详解
    iOS学习—JSON数据解析
    iOS下json的解析 NSJSONSerialization
    NSJSONSerialization介绍
    [iOS经典面试题]用变量a给出下面的定义
    sizeToFit()使用心得
    李洪强-C语言5-函数
    【C语言】10-字符和字符串常用处理函数
    cocos2d-x 2.x 支持多个方向屏幕翻转
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/9115889.html
Copyright © 2020-2023  润新知