CodeForces 1303G-Suma de sumas de prefijos (punto divide y vencerás + Li Chaoshu)

Título

Dale un árbol, cada punto tiene un poco de peso, encuentra un camino u 1, u 2, ... Uk u_1, u_2, ... u_ktu1,tu2,. . . tuk获 Puntuaciones au 1, au 2, .. .auk a_ {u_1}, a_ {u_2}, ... a_ {u_k}unatu1,unatu2,. . . unatuk. Para maximizar la suma de prefijo de su suma de prefijo, encuentre el valor máximo.

Ideas para resolver problemas

El problema de la ruta en el árbol se resolverá mediante la división de puntos y conquistar. Con la idea de dividir y conquistar puntos, cómo fusionar la ruta actual y la información de la ruta existente.
Considere dos matrices a 1, a 2 ... An y b 1, b 2, ... Bm. {a_1, a_2 ... a_n} y {b_1, b_2, ... b_m}.una1,una2. . . unanY b1,si2,. . . sim. Sea lasumade los elementossuma sumas u m , la suma de la suma del prefijo esxsum xsumx s u m . Luego conéctese aa 1, a 2 ... An, b 1, b 2, ... Bm {a_1, a_2 ... a_n, b_1, b_2, ... b_m}una1,una2. . . unan,si1,si2,. . . sim之后 总 的xsum = xsuma + m ∗ suma + xsumb xsum = xsum_a + m * sum_a + xsum_bx s u m=x s u muna+metros u muna+x s u mb.
Esto es sobre mmUna función de m . Mantenemosxsuma (constante) xsum_a (constante)en LiChaoshux s u muna( Número constante ) ySUMA (pendiente) sum_a (pendiente)s u muna( Ramp rate ) , y cuando la consulta usandosumb ym ym sum_bs u mbY m va a Li Chao Shu a consultammEl valor máximo de m puntos.
Luego, al consultar, siga la consulta, y luego al revés, puede obtener toda la información en un determinado subárbol como la consulta, y la información de otros subárboles se almacena como una función lineal en LiChaoshucorrespondiente axsum xsumx s u m .
Tenga en cuenta que cuando el tamaño de todo el árbol es 2, también debe verificar el resto de la información almacenada en el árbol Li Chao, y luego el nodo raíz se usa como el valor de la información de la consulta.

#include<vector>
#include<iostream>
#define ll long long
#define P pair<int, int>
#define Pll pair<ll, ll>
#define pb push_back
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
const int maxn = 2e5 + 50;
struct LiChao_segment_tree{
    
    
    inline ll f(ll k, int x, ll b){
    
    
        return k*x+b;
    }
    ll k[maxn<<2], b[maxn<<2]; int lz[maxn<<2];
    int N;
    void init(int n){
    
    
        N = n; lz[1] = 1; k[1] = b[1] = 0;
    }
    inline void down(int rt){
    
    
        if(!lz[rt]) return;
        lz[rt<<1] = lz[rt<<1|1] = 1;
        k[rt<<1] = k[rt<<1|1] = b[rt<<1] = b[rt<<1|1] = 0;
        lz[rt] = 0;//AHHHHHHH!!
        return;
    }
    void update(int rt, int l, int r, ll ck, ll cb){
    
    
        if(f(ck, mid, cb) > f(k[rt], mid, b[rt])) swap(k[rt], ck), swap(b[rt], cb);
        if(l == r) return;
        down(rt);
        if(ck > k[rt]) update(rson,ck, cb);//要传的斜率较大,去右边
        else update(lson, ck, cb);//否则去左边
    }
    ll qry(int rt, int l, int r, int x){
    
    
        ll ans = f(k[rt], x, b[rt]);
        if(l == r) return ans;
        down(rt);
        if(x <= mid) ans = max(ans, qry(lson, x));
        else ans = max(ans, qry(rson, x));
        return ans;
    }
}T;
vector<int> g[maxn];
int  sz[maxn], ms[maxn], vis[maxn], totsz;
ll a[maxn];
int n, rt;
ll ans = 0;
void get_rt(int u, int fa){
    
    
    sz[u] = 1; ms[u] = 0;
    for(int v: g[u]){
    
    
        if(v == fa || vis[v]) continue;
        get_rt(v, u);
        sz[u] += sz[v];
        ms[u] = max(ms[u], sz[v]);
    }
    ms[u] = max(ms[u], totsz - sz[u]);
    if(ms[rt] > ms[u]) rt = u;
}
void init()
{
    
    
    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);
    }
    for(int i = 1; i <= n; ++i) scanf("%I64d", &a[i]);
    totsz = n;
}
void qry(int u, int fa, ll sum, ll xsum, int d){
    
    
    int f = 0; d++; sum += a[u]; xsum += sum;
    for(int v: g[u]){
    
    
        if(vis[v] || v == fa) continue;
        f = 1;
        qry(v, u, sum, xsum, d);
    }
    if(f) return;
    ans = max(ans, xsum + T.qry(1, 1, T.N, d));
}
void update(int u, int fa, ll sum, ll xsum, int d){
    
    
    d++; sum += a[u]; xsum += d*a[u];
    int f = 0;
    for(int v: g[u]){
    
    
        if(vis[v] || v == fa) continue;
        f = 1;
        update(v, u, sum, xsum, d);
    }
    if(f) return;
    T.update(1, 1, T.N, sum, xsum);
}
void cal(int u, int cursize){
    
    
    T.init(cursize);
    for(int i = 0; i < g[u].size(); ++i){
    
    
        int v = g[u][i];
        if(vis[v]) continue;
        qry(v, u, a[u], a[u], 1);
        update(v, u, 0, 0, 0);
    }
    ans = max(ans, a[u] + T.qry(1, 1, T.N, 1));
    T.init(cursize);
    for(int i = g[u].size()-1; i >= 0; --i){
    
    
        int v = g[u][i];
        if(vis[v]) continue;
        qry(v, u, a[u], a[u], 1);
        update(v, u, 0, 0, 0);
    }
}
void gao(int u, int cursize)
{
    
    
    vis[u] = 1;
    cal(u, cursize);
    for(int v: g[u]){
    
    
        if(vis[v]) continue;
        totsz = sz[v] < sz[u] ? sz[v] : cursize - sz[u];
        rt = 0;
        get_rt(v, 0);
        gao(rt, totsz);
    }
}
void sol(){
    
    

    rt = 0; ms[rt] = n+1;
    get_rt(1, 0);
    gao(rt, n);
    cout<<ans<<endl;
}
int main()
{
    
    
    //freopen("testdata.in", "r", stdin);
	init();sol();
}
/*
4
4 2
3 2
4 1
1 3 3 7
*/

Supongo que te gusta

Origin blog.csdn.net/qq_43202683/article/details/104354123
Recomendado
Clasificación