BZOJ 4515 [Sdoi2016]游戏

来源:互联网 发布:2017网络规划设计师 编辑:程序博客网 时间:2024/05/17 06:49

李超线段树

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

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

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

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

#include<cstdio>#include<algorithm>#define N 100005using 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
原创粉丝点击