• BZOJ1767/Gym207383I CEOI2009 Harbingers 斜率优化、可持久化单调栈、二分


    传送门——BZOJCH

    传送门——VJ

    注:本题在BZOJ上是权限题,在Gym里面也不能直接看,所以只能在VJ上交了……


    不难考虑到这是一个(dp)

    (dep_x)表示(x)在树上的带权深度,(parent_x)表示(x)的祖先节点集合,(f_x)表示点(x)的答案

    那么

    (f_x = minlimits_{i in parent_x}{f_i + V_x imes (dep_x - dep_i)} + S_x = minlimits_{i in parent_x}{- dep_i imes V_x + f_i} + S_x + V_x imes dep_x)

    这是一个典型的斜率优化模型,斜率为(-dep_i),截距为(f_i),自变量为(V_x)

    首先对于树上的一条链,(V_x)并不单调,所以我们不能使用单调队列。但是因为边权非负,所以斜率单调不降,也就意味着我们不需要使用平衡树,而只需要使用单调栈+二分就可以解决维护凸包的问题。

    再者,因为不是序列上的问题,那么计算到某一个点后,当前的单调栈会被其所有儿子共用,而儿子不止一个,所以我们需要将单调栈持久化以应对多次的使用。使用可持久化线段树解决这个问题。

    最后注意:在维护凸包时不能暴力(pop)当前不满足条件的直线,而是应该在单调栈上二分找到最后一个在凸包上的直线。这样才能够保证复杂度。

    总复杂度为(O(nlog^2n))

    下面是一份常数巨大的代码

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<ctime>
    #include<cctype>
    #include<algorithm>
    #include<cstring>
    #include<iomanip>
    #include<queue>
    #include<map>
    #include<set>
    #include<bitset>
    #include<stack>
    #include<vector>
    #include<cmath>
    #define int long long
    #define mid ((l + r) >> 1)
    #define lch Tree[x].l
    #define rch Tree[x].r
    //This code is written by Itst
    using namespace std;
    
    inline int read(){
        int a = 0;
        char c = getchar();
        bool f = 0;
        while(!isdigit(c) && c != EOF){
            if(c == '-')
                f = 1;
            c = getchar();
        }
        if(c == EOF)
            exit(0);
        while(isdigit(c)){
            a = a * 10 + c - 48;
            c = getchar();
        }
        return f ? -a : a;
    }
    
    const int MAXN = 1e5 + 7;
    struct Edge{
        int end , upEd , w;
    }Ed[MAXN << 1];
    struct line{
        int k , b;
        line(int _k = 0 , int _b = 0):k(_k) , b(_b){}
    };
    struct node{
        int l , r;
        line L;
    }Tree[MAXN * 30];
    int rt[MAXN] , head[MAXN] , ans[MAXN] , dep[MAXN] , V[MAXN] , S[MAXN] , cnt[MAXN];
    int cntN , cntEd , N , maxN;
    
    inline void addEd(int a , int b , int c){
        Ed[++cntEd].end = b;
        Ed[cntEd].upEd = head[a];
        Ed[cntEd].w = c;
        head[a] = cntEd;
    }
    
    inline int calc(line l , int x){
        return l.k * x + l.b;
    }
    
    line getL(int x , int l , int r , int tar){
        if(l == r)
            return Tree[x].L;
        if(mid >= tar)
            return getL(lch , l , mid , tar);
        return getL(rch , mid + 1 , r , tar);
    }
    
    void ins(int &x , int l , int r , int tar , line L){
        int t = ++cntN;
        Tree[t] = Tree[x];
        x = t;
        if(l == r){
            Tree[t].L = L;
            return;
        }
        if(mid >= tar)
            ins(lch , l , mid , tar , L);
        else
            ins(rch , mid + 1 , r , tar , L);
    }
    
    inline int erf(int id , int x){
        int L = 1 , R = cnt[id];
        while(L < R){
            int MID = (L + R) >> 1;
            if(calc(getL(rt[id] , 1 , N , MID) , x) > calc(getL(rt[id] , 1 , N , MID + 1) , x))
                L = MID + 1;
            else
                R = MID;
        }
        return calc(getL(rt[id] , 1 , N , L) , x);
    }
    
    inline bool ifpop(line L1 , line L2 , line L3){
        return (long double)(L1.b - L2.b) * (L3.k - L1.k) >= (long double)(L1.b - L3.b) * (L2.k - L1.k);
    }
    
    inline int erf2(int id , line l){
    	int L = 1 , R = cnt[id];
    	while(L < R){
    		int MID = (L + R) >> 1;
    		if(ifpop(getL(rt[id] , 1 , N , MID) , getL(rt[id] , 1 , N , MID + 1) , l))
    			R = MID;
    		else
    			L = MID + 1;
    	}
    	return L;
    }
    
    void dfs(int x , int p){
        bool f = 1;
        if(x != 1){
            rt[x] = rt[p];
            cnt[x] = cnt[p];
            ans[x] = erf(x , V[x]) + dep[x] * V[x] + S[x];
            line p = getL(rt[x] , 1 , N , cnt[x]);
            if(p.k == -dep[x])
                if(p.b > ans[x])
                    --cnt[x];
                else
                    f = 0;
            if(f)
                cnt[x] = erf2(x , line(-dep[x] , ans[x]));
        }
        if(f)
            ins(rt[x] , 1 , N , ++cnt[x] , line(-dep[x] , ans[x]));
        for(int i = head[x] ; i ; i = Ed[i].upEd)
            if(Ed[i].end != p){
                dep[Ed[i].end] = dep[x] + Ed[i].w;
                dfs(Ed[i].end , x);
            }
    }
    
    signed main(){
    #ifndef ONLINE_JUDGE
        freopen("in","r",stdin);
        freopen("out","w",stdout);
    #endif
        N = read();
        for(int i = 1 ; i < N ; ++i){
            int a = read() , b = read() , c = read();
            addEd(a , b , c);
            addEd(b , a , c);
        }
        for(int i = 2 ; i <= N ; ++i){
            S[i] = read();
            V[i] = read();
        }
        dfs(1 , 0);
        for(int i = 2 ; i <= N ; ++i)
            cout << ans[i] << ' ';
        return 0;
    }
    
  • 相关阅读:
    2016 大连网赛
    LightOJ 1012 简单bfs,水
    Pyhton学习——Day30
    Client初见——python
    Server初见——python
    Pyhton学习——Day29
    Pyhton学习——Day28
    Pyhton学习——Day27
    Pyhton学习——Day26
    函数基础作业
  • 原文地址:https://www.cnblogs.com/Itst/p/10326921.html
Copyright © 2020-2023  润新知