BZOJ 4515 [Sdoi2016]游戏

李超线段树

就是区间cmin一次函数,只不过被搬到树上来了。李超线段树标记永久化搞一搞就行了。O(nlog^3)

具体地。每一个节点表示一个区间,存储一个一次函数,表示在该区间的优势一次函数,即能取到最小值的一次函数。更新的时候一整条往下扫一下即可。

大年初一凌晨敲道农题压压惊

UPD(2017.4.8):震惊!突然发现自己下面的代码是错的。注意下面代码里标记的地方。正确的代码附在后面了。话说这题数据好像不够强啊,这个都没卡掉……

#include<cstdio>
#include<algorithm>
#define N 100005
using namespace std;
namespace runzhe2000
{
    typedef long long ll;
    int in()
    {
        int r = 0, p = 0; char c = getchar();
        for(; c < '0' || c > '9'; c = getchar()) if(c == '-') p = 1;
        for(; c >='0' && c <='9'; c = getchar()) r = r * 10 + c - '0';
        return p ? -r : r; 
    }
    ll ans, dis[N];
    int n, m, last[N], ecnt, top[N], siz[N], son[N], fa[N], dep[N], pos[N], repos[N], timer;
    struct edge{int next, to, val;}e[N<<1];
    struct seg{ll K, B, mi;}t[N<<2];
    void addedge(int a, int b, int c){e[++ecnt] = (edge){last[a], b, c}; last[a] = ecnt;}
    void dfs1(int x)
    {
        dep[x] = dep[fa[x]] + 1; siz[x] = 1; 
        for(int i = last[x]; i; i = e[i].next)
        {
            int y = e[i].to; if(y == fa[x])continue;
            fa[y] = x; dis[y] = dis[x] + e[i].val;  dfs1(y);
            siz[x] += siz[y]; if(siz[y] > siz[son[x]]) son[x] = y;
        }
    }
    void dfs2(int x)
    {
        top[x] = son[fa[x]] == x ? top[fa[x]] : x;
        pos[x] = ++timer; repos[timer] = x;
        if(son[x]) dfs2(son[x]); else return;
        for(int i = last[x]; i; i = e[i].next)
        {
            int y = e[i].to;
            if(y == fa[x] || y == son[x]) continue;
            dfs2(y);
        }
    }
    int get_lca(int a, int b)
    {
        for(; top[a] != top[b]; )
        {
            if(dep[top[a]] < dep[top[b]]) swap(a, b);
            a = fa[top[a]];
        }
        return dep[a] < dep[b] ? a : b; 
    }
    void build(int x, int l, int r)
    {
        t[x].K = 0; t[x].B = t[x].mi = 123456789123456789ll;
        if(l == r) return;
        int mid = (l+r)>>1;
        build(x<<1,l,mid); build(x<<1|1,mid+1,r);
    }
    void pushup(int x, int l, int r)
    {
        ll f_lef = t[x].K * dis[repos[l]] + t[x].B, f_rig = t[x].K * dis[repos[r]] + t[x].B;
        if(l == r)t[x].mi = f_lef;
        else t[x].mi = min(min(f_lef, f_rig), min(t[x<<1].mi, t[x<<1|1].mi));
    }
    void modi(int x, int l, int r, ll K, ll B)
    {
        ll f1_lef = t[x].K * dis[repos[l]] + t[x].B, f1_rig = t[x].K * dis[repos[r]] + t[x].B;
        ll f2_lef = K * dis[repos[l]] + B, f2_rig = K * dis[repos[r]] + B;
        if(f2_lef >= f1_lef && f2_rig >= f1_rig) return;
        if(f2_lef <= f1_lef && f2_rig <= f1_rig) {t[x].K = K; t[x].B = B;}
        else {int mid = (l+r)>>1; modi(x<<1,l,mid,K,B); modi(x<<1|1,mid+1,r,K,B);}//这里把一个一次函数递归进两个子树,虽然在当前节点该一次函数有一定的优势区间,似乎能返回。但递归下去之后,子树的一次函数是不确定的,因此可能进一步递归下去而不能返回,可能退化为O(n)。
        pushup(x,l,r);
    }
    void modi(int x, int l, int r, int ql, int qr, ll K, ll B)
    {
        if(ql <= l && r <= qr){modi(x,l,r,K,B);return;}
        int mid = (l+r)>>1;
        if(ql <= mid) modi(x<<1,l,mid,ql,qr,K,B);
        if(mid <  qr) modi(x<<1|1,mid+1,r,ql,qr,K,B);
        pushup(x,l,r);
    }
    void query(int x, int l, int r, int ql, int qr)
    {
        if(ql <= l && r <= qr)
        {
            ans = min(ans, t[x].mi);
            return;
        }
        int L = max(l, ql), R = min(r, qr);
        ans = min(ans, min((ll)t[x].K*dis[repos[L]]+t[x].B, (ll)t[x].K*dis[repos[R]]+t[x].B));
        int mid = (l+r)>>1;
        if(ql <= mid)query(x<<1,l,mid,ql,qr);
        if(mid <  qr)query(x<<1|1,mid+1,r,ql,qr);
    }

    void main()
    {
        n = in(); m = in();
        for(int i = 1, a, b, c; i < n; i++)
        {
            a = in(), b = in(), c = in();
            addedge(a, b, c); addedge(b, a, c);
        }
        dfs1(1); dfs2(1);
        build(1,1,n);
        for(int _m = 1, opt, s, t, S, T, a, b; _m <= m; _m++)
        {
            opt = in();
            if(opt == 1)
            {
                S = in(), T = in(), a = in(), b = in(); 
                int lca = get_lca(S, T); ll K, B;
                K = -a; B = b + (ll)a * dis[S]; 
                for(s = S; top[s] != top[lca]; s = fa[top[s]])modi(1,1,n,pos[top[s]], pos[s], K, B); modi(1,1,n,pos[lca], pos[s], K, B);
                K = a;  B = b + (ll)a * (dis[S] - 2*dis[lca]);
                for(t = T; top[t] != top[lca]; t = fa[top[t]])modi(1,1,n,pos[top[t]], pos[t], K, B); modi(1,1,n,pos[lca], pos[t], K, B); 
            }
            else
            {
                s = in(), t = in();
                int lca = get_lca(s, t); ans = 123456789123456789ll;
                for(; top[s] != top[lca]; s = fa[top[s]]) query(1,1,n,pos[top[s]], pos[s]); query(1,1,n,pos[lca], pos[s]);
                for(; top[t] != top[lca]; t = fa[top[t]]) query(1,1,n,pos[top[t]], pos[t]); query(1,1,n,pos[lca], pos[t]);
                printf("%lld\n",ans);
            }
        }
    }
}
int main()
{
    runzhe2000::main();
}

以下正解,注意标注的地方

#include<cstdio>
#include<algorithm>
#define N 200005
#define cmin(u,v) ((u)>(v)?(u)=(v):0)
using namespace std;
namespace runzhe2000
{
    typedef double db;
    typedef long long ll;
    const ll INF = 123456789123456789ll;
    ll read()
    {
        ll r = 0; int p = 0; char c = getchar();
        for(; c < '0' || c > '9'; c = getchar()) c == '-' ? p = 1 : 0;
        for(; c >='0' && c <='9'; r = r*10+c-'0', c = getchar());
        return p ? -r : r;
    }
    ll ans, dis[N];
    int n, m, ecnt, timer, last[N], dep[N], siz[N], son[N], top[N], fa[N], beg[N], rebeg[N];
    struct edge{int next, to; ll val;}e[N<<1];

    void addedge(int a, int b, ll c)
    {
        e[++ecnt] = (edge){last[a], b, c};
        last[a] = ecnt;
    }
    void dfs1(int x)
    {
        dep[x] = dep[fa[x]] + 1; siz[x] = 1;
        for(int i = last[x]; i; i = e[i].next)
        {
            int y = e[i].to; if(y == fa[x]) continue;
            fa[y] = x; dis[y] = dis[x] + e[i].val; dfs1(y); siz[x] += siz[y];
            siz[y] > siz[son[x]] ? son[x] = y : 0;
        }
    }
    void dfs2(int x)
    {
        top[x] = son[fa[x]]==x?top[fa[x]] : x;
        rebeg[beg[x] = ++timer] = x; if(son[x]) dfs2(son[x]);
        for(int i = last[x]; i; i = e[i].next)
        {
            int y = e[i].to; if(y == fa[x] || y == son[x]) continue;
            dfs2(y); 
        }
    }
    int get_lca(int a, int b)
    {
        for(; top[a] != top[b]; )
        {
            if(dep[top[a]] < dep[top[b]]) b = fa[top[b]];
            else a = fa[top[a]];
        }
        return dep[a] < dep[b] ? a : b;
    }

    struct seg
    {
        ll k, b, v;
    }t[N*5];
    void build(int x, int l, int r)
    {
        t[x].k = 0; t[x].v = t[x].b = INF; if(l == r) return; int mid = (l+r)>>1;
        build(x<<1,l,mid); build(x<<1|1,mid+1,r);
    }
    void pushup(int x, int l, int r)
    {
        ll &k1 = t[x].k, &b1 = t[x].b;
        t[x].v = min(k1 * dis[rebeg[l]] + b1, k1 * dis[rebeg[r]] + b1);
        if( l == r )return;
        t[x].v = min(t[x].v, min(t[x<<1].v, t[x<<1|1].v));
    }
    void do_modi(int x, int l, int r, ll k, ll b)
    {
        ll &k1 = t[x].k, &b1 = t[x].b;
        if(k1 * dis[rebeg[l]] + b1 <= k * dis[rebeg[l]] + b && k1 * dis[rebeg[r]] + b1 <= k * dis[rebeg[r]] + b) return;
        if(k1 * dis[rebeg[l]] + b1 >  k * dis[rebeg[l]] + b && k1 * dis[rebeg[r]] + b1 >  k * dis[rebeg[r]] + b) 
        { k1 = k; b1 = b; pushup(x,l,r); return; } 
        int mid = (l+r)>>1;
        db x_mid = (dis[rebeg[mid]] + dis[rebeg[mid+1]]) / 2.0;
        //注意只能递归进一个子树
        if(k1 * x_mid + b1 > k * x_mid + b) swap(k, k1), swap(b, b1);
        if((db)(b-b1)/(k1-k) < x_mid) do_modi(x<<1,l,mid,k,b);
        else do_modi(x<<1|1,mid+1,r,k,b);
        pushup(x,l,r);
    }
    void modi(int x, int l, int r, int ql, int qr, ll k, ll b)
    {
        if(ql <= l && r <= qr) return do_modi(x,l,r,k,b);
        int mid = (l+r)>>1;
        if(ql <= mid) modi(x<<1,l,mid,ql,qr,k,b);
        if(mid <  qr) modi(x<<1|1,mid+1,r,ql,qr,k,b);
        pushup(x,l,r);
    }
    void add(int x, int y, ll k, ll b)
    {
        for(; top[x] != top[y]; x = fa[top[x]])
            modi(1,1,n,beg[top[x]],beg[x],k,b);
        modi(1,1,n,beg[y],beg[x],k,b);
    }
    void query(int x, int l, int r, int ql, int qr)
    {
        ans = min(ans, t[x].k * dis[rebeg[max(l, ql)]] + t[x].b);
        ans = min(ans, t[x].k * dis[rebeg[min(r, qr)]] + t[x].b);
        if(ql <= l && r <= qr) {cmin(ans, t[x].v); return;}
        int mid = (l+r)>>1;
        if(ql <= mid) query(x<<1, l, mid, ql, qr);
        if(mid <  qr) query(x<<1|1,mid+1, r, ql, qr);
    }
    void ask(int x, int y)
    {
        for(; top[x] != top[y]; x = fa[top[x]])
            query(1,1,n,beg[top[x]],beg[x]);
        query(1,1,n,beg[y],beg[x]);
    }

    void main()
    {
        n = read(); m = read();
        for(int i = 1, a, b, c; i < n; i++)
        {
            a = read(); b = read(); c = read();
            addedge(a, b, c); addedge(b, a, c);
        }
        dfs1(1); dfs2(1); build(1,1,n);
        for(int i = 1, s, t, z; i <= m; i++)
        {
            if(read() == 1) //add
            {
                ll a, b;
                s = read(); t = read(); a = read(); b = read();
                z = get_lca(s, t);
                add(s, z, -a, b+a*dis[s]);
                add(t, z,  a, b-a*(dis[z]*2-dis[s]));
            }
            else // ask
            {
                s = read(); t = read(); z = get_lca(s, t);
                ans = INF;
                ask(s, z);
                ask(t, z);
                printf("%lld\n",ans);
            }
        }
    }
}
int main()
{
    runzhe2000::main();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值