1. 程式人生 > >[BZOJ4515][SDOI2016]遊戲

[BZOJ4515][SDOI2016]遊戲

.com using line -a swap ace link () 下標

bzoj
luogu

description

一棵樹,支持鏈上插入一次函數,詢問鏈上最大值。
\(n,m\le10^5\)

sol

題面已經簡化成這樣了那就是裸的超哥線段樹了吧。註意這裏就算下標是離散的超哥線段樹還是可以做的。
超哥線段樹具體實現原理這裏就不講了因為我也不會
復雜度\(O(n\log^3n)\),顯得有點假,但是能過。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi(){
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
#define ll long long
const int N = 1e5+5;
const ll inf = 123456789123456789ll;
int n,m,to[N<<1],nxt[N<<1],ww[N<<1],head[N],cnt,fa[N],dep[N],sz[N],son[N],top[N],dfn[N],id[N];
ll dis[N],mn[N<<2];
struct line{
    ll k,b;
    ll f(ll x){return k*x+b;}
}t[N<<2];
void link(int u,int v,int w){
    to[++cnt]=v;nxt[cnt]=head[u];ww[cnt]=w;head[u]=cnt;
}
void dfs1(int u,int f){
    fa[u]=f;dep[u]=dep[f]+1;sz[u]=1;
    for (int e=head[u];e;e=nxt[e])
        if (to[e]!=f){
            dis[to[e]]=dis[u]+ww[e];
            dfs1(to[e],u),sz[u]+=sz[to[e]];
            if (sz[to[e]]>sz[son[u]]) son[u]=to[e];
        }
}
void dfs2(int u,int up){
    top[u]=up;id[dfn[u]=++cnt]=u;
    if (son[u]) dfs2(son[u],up);
    for (int e=head[u];e;e=nxt[e])
        if (to[e]!=fa[u]&&to[e]!=son[u])
            dfs2(to[e],to[e]);
}
int lca(int u,int v){
    while (top[u]^top[v]){
        if (dep[top[u]]<dep[top[v]]) swap(u,v);
        u=fa[top[u]];
    }
    return dep[u]<dep[v]?u:v;
}
void build(int x,int l,int r){
    t[x].b=mn[x]=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){
    if (l<r) mn[x]=min(mn[x<<1],mn[x<<1|1]);
    mn[x]=min(mn[x],min(t[x].f(dis[id[l]]),t[x].f(dis[id[r]])));
}
void update(int x,int l,int r,line tmp){
    int mid=l+r>>1;
    if (tmp.f(dis[id[mid]])<t[x].f(dis[id[mid]])) swap(t[x],tmp);
    if (l==r) {pushup(x,l,r);return;}
    if (tmp.k>t[x].k) update(x<<1,l,mid,tmp);
    else update(x<<1|1,mid+1,r,tmp);
    pushup(x,l,r);
}
void modify(int x,int l,int r,int ql,int qr,line tmp){
    if (l>=ql&&r<=qr) {update(x,l,r,tmp);return;}
    int mid=l+r>>1;
    if (ql<=mid) modify(x<<1,l,mid,ql,qr,tmp);
    if (qr>mid) modify(x<<1|1,mid+1,r,ql,qr,tmp);
    pushup(x,l,r);
}
ll query(int x,int l,int r,int ql,int qr){
    if (l>=ql&&r<=qr) return mn[x];
    int mid=l+r>>1;ll res=min(t[x].f(dis[id[ql]]),t[x].f(dis[id[qr]]));
    if (qr<=mid) return min(res,query(x<<1,l,mid,ql,qr));
    if (ql>mid) return min(res,query(x<<1|1,mid+1,r,ql,qr));
    return min(res,min(query(x<<1,l,mid,ql,mid),query(x<<1|1,mid+1,r,mid+1,qr)));
}
int main(){
    n=gi();m=gi();
    for (int i=1;i<n;++i){
        int u=gi(),v=gi(),w=gi();
        link(u,v,w);link(v,u,w);
    }
    dfs1(1,0);cnt=0;dfs2(1,1);build(1,1,n);
    while (m--){
        int op=gi(),u=gi(),v=gi();
        if (op&1){
            ll a=gi(),b=gi();int gg=lca(u,v);
            line tmp=(line){a,(dis[u]-dis[gg]*2)*a+b};
            while (top[v]^top[gg])
                modify(1,1,n,dfn[top[v]],dfn[v],tmp),v=fa[top[v]];
            modify(1,1,n,dfn[gg],dfn[v],tmp);
            tmp=(line){-a,dis[u]*a+b};
            while (top[u]^top[gg])
                modify(1,1,n,dfn[top[u]],dfn[u],tmp),u=fa[top[u]];
            modify(1,1,n,dfn[gg],dfn[u],tmp);       
        }else{
            ll res=inf;
            while (top[u]^top[v]){
                if (dep[top[u]]<dep[top[v]]) swap(u,v);
                res=min(res,query(1,1,n,dfn[top[u]],dfn[u]));
                u=fa[top[u]];
            }
            if (dep[u]>dep[v]) swap(u,v);
            res=min(res,query(1,1,n,dfn[u],dfn[v]));
            printf("%lld\n",res);
        }
    }
    return 0;
}

[BZOJ4515][SDOI2016]遊戲