BZOJ 4515 SDOI2016 游戏

数据结构题就不提示了……

本题很明显的一个思路就是用树剖维护信息 , 对于每一段我们这样记录一个标记: Axi+b , 对于这一段中的每一个节点 p , Xp等于到这一段开头节点的距离。

那么一个重要的问题来啦。 如何下传一个标记呢?如果你做过一道用线段树维护半平面交的题目的话 , 此时的思路就是显然的。 我们假设此时这条线段上躺着一个标记 a1x+b1 现在我们要加一个标记 a2x+b2 。 显然 , 我们只能留一个 , 那么我们要知道哪一个更优。让我们来解不等式:

a1x+b1a2x+b2


诶 , 我们需要分类讨论 ,有几个情况要讨论 , 但大致思路都是我们找到一个分界点 , 那么我们就把这条线段的距离分成了两半 , 这两半的最优情况在不同的标记中取到。现在的问题是 , 我们把谁推下去。 如下图:
这里写图片描述

此时绿色部分第一个标记更优 , 红色部分第二个标记更优 , 那么我们就应该把第一个标记推下去 , 因为它完全被包含在 [L,Mid] 中。

吐槽: RE不止 ,最后发现是爆栈??链状结构我就不多写判断了 , 鉴于出题人习惯于把 i 连向i1我就顺其自然好了

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#include <vector>
#include <deque>
#include <set>
#include <map>
#include <complex>
#include <climits>
#include <cassert>

using namespace std;
typedef long long ll;
const int maxn = 1e5+1e2;
const ll INF = 123456789123456789;

struct edge{ int t; ll v; edge(int t=0 , ll v=0):t(t),v(v){} }; 

int n , m , dfsCnt;
vector<edge> g[maxn];

ll dis[maxn];
int fa[maxn] , Size[maxn] , dep[maxn] , bl[maxn] , id[maxn] , reid[maxn];
void dfs(int x)
{
    Size[x] = 1;
    for(int i=0;i<g[x].size();i++)
    {
        edge& e = g[x][i];
        if(e.t == fa[x]) continue;
        fa[e.t] = x;
        dep[e.t] = dep[x] + 1;
        dis[e.t] = dis[x] + e.v;
        dfs(e.t);
        Size[x] += Size[e.t];
    }
}

void dfs(int x , int num)
{
    id[x] = ++dfsCnt;
    reid[dfsCnt] = x;
    bl[x] = num;
    int mx =0 , w;
    for(int i=0;i<g[x].size();i++)
    {
        edge& e = g[x][i];
        if(e.t == fa[x]) continue;
        if(mx < Size[e.t]) mx = Size[w = e.t];
    }

    if(mx) dfs(w , num);


    for(int i=0;i<g[x].size();i++)
    {
        edge& e = g[x][i];
        if(e.t == fa[x] || e.t == w) continue;
        dfs(e.t , e.t);
    }
}

bool flag[maxn*10];
ll mn[maxn*10] , A[maxn*10] , B[maxn*10];

int lca(int x , int y)
{
    while(bl[x] != bl[y])
    {
        if(dep[bl[x]] > dep[bl[y]]) swap(x , y);
        y = fa[bl[y]];
    }

    return dep[x] < dep[y] ? x : y;
}

void maintain(int o , int l , int r)
{
    if(flag[o]) mn[o] = min(B[o] , A[o]*(dis[reid[r]] - dis[reid[l]])+B[o]);
    if(l!=r) mn[o] = min(mn[o] , min(mn[o*2] , mn[o*2+1]));
}


void giveFlag(int o , int l , int r , ll a , ll b)
{
    if(!flag[o]) A[o] = a , B[o] = b , flag[o] = 1;
    else
    {
        if(A[o] == a || l == r) B[o] = min(B[o] , b);
        else
        {
            int mid = (l+r)/2; ll d , len = dis[reid[mid+1]] - dis[reid[l]];
            if(A[o] < a && B[o] < b) ;
            else if(A[o] > a && B[o] > b) swap(A[o] , a) , swap(B[o] , b);
            else if(A[o] > a && B[o] < b)
            {
                d = (b - B[o])/(A[o] - a);
                if(d <= len)
                {
                    swap(A[o] , a) , swap(B[o] , b);
                    giveFlag(o*2 , l , mid , a , b);
                }
                else giveFlag(o*2+1 , mid+1 , r , a , b+a*len);
            }
            else if(A[o] < a && B[o] > b)
            {
                d = (B[o] - b + a - A[o] - 1)/(a - A[o]);
                if(d <= len) giveFlag(o*2 , l , mid , a , b);
                else 
                {
                    swap(A[o] , a) , swap(B[o] , b);
                    giveFlag(o*2+1 , mid+1 , r , a , b+a*len);
                }
            }
        }
    }

    maintain(o , l , r);
}

void modify(int o , int l , int r , int L , int R , ll a , ll b)
{
    if(L <= l && r <= R) giveFlag(o, l, r, a, b+a*(dis[reid[l]]-dis[reid[L]]));
    else 
    {
        int mid = (l+r)/2;
        if(L <= mid) modify(o*2, l, mid, L, R, a, b);
        if(R >  mid) modify(o*2+1, mid+1, r, L, R, a, b);
    }
    maintain(o, l, r);
}

void modify2(int l , int x , ll a , ll b)
{
    int f;
    while(bl[x] != bl[l])
    {
        f = bl[x];
        modify(1 , 1 , n , id[f] , id[x] , a , a*(dis[f]-dis[l])+b);
        x = fa[f];
    }

    modify(1 , 1 , n , id[l] , id[x] , a , b);
}

void modify(int x , int y , ll a , ll b)
{
    int l = lca(x , y);
    modify2(l , x , -a , b+a*(dis[x]-dis[l]));
    modify2(l , y ,  a , b+a*(dis[x]-dis[l]));
}

ll query(int o , int l , int r , int L , int R)
{
    ll res = INF;
    if(flag[o]) 
    {
        int ll = max(l, L);
        int rr = min(r, R);
        res = min(A[o]*(dis[reid[ll]]-dis[reid[l]]) , A[o]*(dis[reid[rr]]-dis[reid[l]])) + B[o];
    }

    if(L <= l && r <= R) return min(res, mn[o]);
    else 
    {
        int mid = (l+r)/2;
        if(L <= mid) res = min(res , query(o*2, l, mid, L, R));
        if(R >  mid) res = min(res , query(o*2+1, mid+1, r, L, R));
        return res;
    }
}

ll query(int x , int y)
{
    ll res = INF;

    while(bl[x] != bl[y])
    {
        if(dep[bl[x]] > dep[bl[y]]) swap(x, y);

        res = min(res , query(1, 1, n, id[bl[y]], id[y]));
        y = fa[bl[y]];
    }

    if(dep[x] > dep[y]) swap(x, y);
    return min(res, query(1, 1, n, id[x], id[y]));
}

int main()
{   
    cin>>n>>m;

    bool line = true;
    for(int i=1;i<n;i++)
    {
        int a , b; ll c;
        scanf("%d%d%lld" , &a , &b , &c);

        g[a].push_back(edge(b , c));
        g[b].push_back(edge(a , c));
        if(b != a+1) line = false;
    }

    if(line)
    {
        for(int i=1;i<=n;i++) 
        {
            fa[i] = i-1; Size[i] = n+1-i; dep[i] = i; id[i] = reid[i] = i; bl[i] = 1;
            for(int j=0;j<g[i].size();j++) if(g[i][j].t == i-1) dis[i] = dis[i-1]+g[i][j].v;
        }
    }
    else
    dfs(1),
    dfs(1 , 1);

    for(int i=0;i<maxn*10;i++) mn[i] = INF;

    int op , s , t; ll a , b;
    while(m--)
    {
        scanf("%d" , &op);
        if(op == 1)
        {
            scanf("%d%d%lld%lld" , &s , &t , &a , &b);
            modify(s, t, a, b);
        }
        else 
        {
            scanf("%d%d" , &s , &t);
            printf("%lld\n" , query(s, t));
        }
    }

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值