BZOJ4515: [Sdoi2016]游戏

来源:互联网 发布:淘宝都市丽人 编辑:程序博客网 时间:2024/06/05 07:26

传送门(这篇写得比我好

qwq
s到t的链可以拆成两条纵链
令dis[x]表示x到根的距离
对于一条纵链上的一个点x,添加的数就可以看成
(dis[x]-dis[t])* k+b
=dis[x]*k-dis[t]*k+b
=k*dis[x]+B
很像直线的表达式y=kx+b
树剖,问题变成线段树维护多条直线在区间内的最小值
对于一条链,因为这个区间内的dis是递增的即x坐标递增,这个操作相当于给线段树一个区间上覆盖一条直线
在区间上打永久化标记为覆盖这个区间的直线,当遇到新的直线时,设加入直线f1,当前覆盖这个区间的直线f2,如果f1(l)< f2(l)&&f1(r)< f2(r) 那么可以用f1代替f2,都大于则没有用,否则递归下去,因为最多只有一个交点,这个交点不在左就在右,所以可以保证复杂度

code:

#include<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>#define ll long longusing namespace std;inline ll _min(const ll a,const ll b){return a<b?a:b;}inline void down(ll &x,const ll &y){if(x>y)x=y;}const int maxn = 210000;const int maxm = 210000;const ll inf = 123456789123456789ll;int n,m;struct edge{    int y,c,nex;    edge(){}    edge(const int _y,const int _c,const int _nex){y=_y;c=_c;nex=_nex;}}a[maxn<<1]; int len,fir[maxn];inline void ins(const int x,const int y,const int c){a[++len]=edge(y,c,fir[x]);fir[x]=len;}ll dis[maxn];int f[maxn],top[maxn],siz[maxn],son[maxn],dep[maxn],w[maxn];void dfs(const int x){    siz[x]=1;    for(int k=fir[x];k;k=a[k].nex)    {        const int y=a[k].y;        if(y!=f[x])        {            dep[y]=dep[x]+1; dis[y]=dis[x]+(ll)a[k].c;            f[y]=x;            dfs(y);            if(siz[son[x]]<siz[y]) son[x]=y;            siz[x]+=siz[y];        }    }}int z;ll s[maxn];void build(const int x,const int tp){    s[w[x]=++z]=dis[x]; top[x]=tp;    if(son[x]) build(son[x],tp);    for(int k=fir[x];k;k=a[k].nex)    {        const int y=a[k].y;        if(y!=f[x]&&y!=son[x])            build(y,y);    }}struct segment{    bool flag;    ll a,b,mn;    segment(){flag=false;mn=inf;}}seg[maxn<<2];int lx,rx;ll fa,fb;void up(const int x){    int lc=x<<1,rc=lc|1;    down(seg[x].mn,_min(seg[lc].mn,seg[rc].mn));}void upd(const int x,const int l,const int r){    if(rx<l||r<lx) return;    if(lx<=l&&r<=rx)    {        ll cl=s[l]*fa+fb,cr=s[r]*fa+fb;        if(seg[x].flag)         {            ll cl2=s[l]*seg[x].a+seg[x].b,cr2=s[r]*seg[x].a+seg[x].b;            if(cl>=cl2&&cr>=cr2) return;            else if( (cl<cl2&&cr>=cr2)||(cl>=cl2&&cr<cr2) )            {                int mid=l+r>>1,lc=x<<1,rc=lc|1;                upd(lc,l,mid); upd(rc,mid+1,r);                up(x); return;            }        }        seg[x].flag=true;        seg[x].a=fa,seg[x].b=fb;        down(seg[x].mn,_min(cl,cr));        return;    }    int mid=l+r>>1,lc=x<<1,rc=lc|1;    upd(lc,l,mid); upd(rc,mid+1,r);    up(x);}ll ret;void query(const int x,const int l,const int r){    if(rx<l||r<lx) return;    if(lx<=l&&r<=rx) { down(ret,seg[x].mn); return ; }    int mid=l+r>>1,lc=x<<1,rc=lc|1;    if(seg[x].flag)    {        ll cl=s[max(lx,l)]*seg[x].a+seg[x].b,cr=s[min(rx,r)]*seg[x].a+seg[x].b;        down(ret,_min(cl,cr));    }    query(lc,l,mid); query(rc,mid+1,r);}int LCA(int x,int y){    int f1=top[x],f2=top[y];    while(f1!=f2)    {        if(dep[f1]<dep[f2])  swap(f1,f2),swap(x,y);        x=f[f1],f1=top[x];    }    return dep[x]<dep[y]?x:y;}void change(int S,int T,int A,int B){    int tp=LCA(S,T),ft=top[tp];    int x=S,f1=top[x];    while(dep[x]>=dep[tp])    {        if(f1==ft) f1=tp;        fa=-A,fb=B+(ll)A*dis[S],lx=w[f1],rx=w[x],upd(1,1,n);        x=f[f1],f1=top[x];    }    int y=T,f2=top[y];    while(dep[y]>=dep[tp])    {        if(f2==ft) f2=tp;        fa=A,fb=B+(ll)A*(dis[S]-dis[tp]*2ll),lx=w[f2],rx=w[y],upd(1,1,n);        y=f[f2],f2=top[y];    }}ll solve(int x,int y){    ll re=inf;    int f1=top[x],f2=top[y];    while(f1!=f2)    {        if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);        lx=w[f1],rx=w[x],ret=inf,query(1,1,n);        down(re,ret);        x=f[f1],f1=top[x];    }    if(dep[x]>dep[y]) swap(x,y);    lx=w[x],rx=w[y],ret=inf,query(1,1,n);    down(re,ret);    return re;}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<n;i++)    {        int x,y,c; scanf("%d%d%d",&x,&y,&c);        ins(x,y,c); ins(y,x,c);    }    dep[1]=1; dfs(1);    build(1,1);    for(int i=1;i<=m;i++)    {        int type,s,t; scanf("%d%d%d",&type,&s,&t);        if(type==1)        {            int A,B; scanf("%d%d",&A,&B);            change(s,t,A,B);        }        else printf("%lld\n",solve(s,t));    }    return 0;}