题目描述:
雾.
题目分析:
首先可以把修改转换一下,因为那个dis非常不爽。显然s~t的路径有s~lca和lca~t组成。令d[x]表示x的深度,对于s~lca上面的点,修改的值相当于a*(d[s]-d[x])+b=-a*d[x]+(b-a*d[s])
lca~t上面的点的值相当于a*(d[s]+d[x]-2*d[lca])+b=a*d[x]+(b+a*(d[s]-d[lca]*2))
这样就可以得到新的a’和b’,然后一个点的值就相当于a’*d[x]+b’了,这样就只和a’,b’和d[x]有关了。
注意到在树链剖分对应的线段树区间中,相连的一部分它们在树种也是相连的,这样就满足d[]单调递增
观察a’*d[x]+b’,发现这相当于直线f(x)=a’x+b在d[x](两个x不是一个意思)处的取值!
那么就相当于用线段树维护一个区间中的若干条直线在每个部分的最小值。
不妨考虑标记永久化(这里只是一定程度上的永久化但还是要下传的)。让线段树中的一个节点只对应一条直线,那么如果在这个区间加入一条直线怎么办呢?要分类讨论,设新加入的f1(x)=k1x+b1,原来的f2(x)=k2x+b2,左端点为l,右端点为r,那么有:
1.f1(d[l])
题目链接:
Ac 代码:
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <ctime>
#define ll long long
const int maxm=1e6+100;
const ll inf=123456789123456789ll;
int head[maxm],net[maxm],to[maxm],cost[maxm],cnt;
int son[maxm],deep[maxm],fa[maxm],top[maxm],rank[maxm],id[maxm],size[maxm],root,siz;
int n,m;
ll dis[maxm],v[maxm],minx[maxm];
struct node{
ll k,b;
int s;
node(ll K=0,ll B=0,int S=0){k=K;b=B;s=S;}
ll calc(int u)
{
ll dist=dis[u]-dis[s];
return k*dist+b;
}
}st[maxm*4];
void addedge(int x,int y,int w)
{
cnt++;
to[cnt]=y,net[cnt]=head[x],head[x]=cnt,cost[cnt]=w;
}
void dfs1(int now,int f,int dep,int last)
{
fa[now]=f,deep[now]=dep,size[now]=1;
dis[now]=dis[f]+last;
for(int i=head[now];i;i=net[i])
if(to[i]!=f)
{
dfs1(to[i],now,dep+1,cost[i]);
size[now]+=size[to[i]];
if(size[to[i]]>size[son[now]]) son[now]=to[i];
}
}
void dfs2(int now,int t)
{
rank[id[now]=++siz]=now;
top[now]=t;
if(son[now]) dfs2(son[now],t);
for(int i=head[now];i;i=net[i])
if(!id[to[i]])
dfs2(to[i],to[i]);
}
void build(int o,int l,int r)
{
st[o]=(node){0,inf,0};
minx[o]=inf;
if(l>=r) return;
int mid=(l+r)>>1;
build((o<<1),l,mid),build((o<<1)|1,mid+1,r);
//minx[o]=std::min(minx[(o<<1)],minx[(o<<1)|1]);
}
int LCA(int u,int v)
{
while(top[u]!=top[v])
{
if(deep[top[u]]<deep[top[v]]) std::swap(u,v);
u=fa[top[u]];
}
return deep[u]<deep[v]?u:v;
}
void insert(int o,int l,int r,node ins)
{
ll ans=std::min(ins.calc(rank[l]),ins.calc(rank[r]));
node tmp=st[o];
if(l==r)
{
if(ans<st[o].calc(rank[l])) st[o]=ins,minx[o]=ans;
return;
}
int mid=(l+r)>>1;
ans=std::min(ans,minx[o]);
if(ins.k>tmp.k) std::swap(ins,tmp);
if (ins.calc(rank[mid])<tmp.calc(rank[mid]))
{
st[o]=ins,minx[o]=std::min(minx[o],ans);
insert((o<<1),l,mid,tmp);
}
else
{
st[o]=tmp,minx[o]=std::min(minx[o],ans);
insert((o<<1)|1,mid+1,r,ins);
}
}
void change(int o,int l,int r,int ql,int qr,node ins)
{
if(ql<=l&&r<=qr)
{
insert(o,l,r,ins);
return;
}
int mid=(l+r)>>1;
if(ql<=mid) change((o<<1),l,mid,ql,qr,ins);
if(qr>mid) change((o<<1)|1,mid+1,r,ql,qr,ins);
minx[o]=std::min(minx[o],std::min(minx[(o<<1)],minx[(o<<1)|1]));
}
ll ask(int o,int l,int r,int ql,int qr)
{
int askl=std::max(ql,l),askr=std::min(r,qr);
ll ans=std::min(st[o].calc(rank[askl]),st[o].calc(rank[askr]));
//printf("%d %d %d %d %d\n",o,l,r,ql,qr);
if(ql<=l&&r<=qr) return std::min(ans,minx[o]);
int mid=(l+r)>>1;
if (ql<=mid) ans=std::min(ans,ask((o<<1),l,mid,ql,qr));
if (qr>mid) ans=std::min(ans,ask((o<<1)|1,mid+1,r,ql,qr));
return ans;
}
void treechange(int u,int v,ll A,ll B)
{
node ins;
int lca=LCA(u,v),s=u;
bool uod=1;
ll base;
while(top[u]!=top[v])
{
if(deep[top[u]]<deep[top[v]]) std::swap(u,v),uod^=1;
base=dis[top[u]]+dis[s]-2*dis[lca];
if(uod==1) base=dis[s]-dis[top[u]];
base=A*base+B;
if(!uod) ins=(node){A,base,top[u]};
else ins=(node){-A,base,top[u]};
change(1,1,n,id[top[u]],id[u],ins);
u=fa[top[u]];
}
if(deep[u]>deep[v]) std::swap(u,v);
else uod^=1;
base=dis[u]+dis[s]-2*dis[lca];
if (uod) base=dis[s]-dis[u];
base=A*base+B;
if(!uod) ins=(node){A,base,u};
else ins=(node){-A,base,u};
change(1,1,n,id[u],id[v],ins);
}
ll treeask(int u,int v)
{
ll ans=inf;
while(top[u]!=top[v])
{
if(deep[top[u]]<deep[top[v]]) std::swap(u,v);
ans=std::min(ans,ask(1,1,n,id[top[u]],id[u]));
u=fa[top[u]];
}
if(deep[u]<deep[v]) std::swap(u,v);
ans=std::min(ans,ask(1,1,n,id[v],id[u]));
return ans;
}
int main()
{
//freopen("menci_game.in","r",stdin);
//freopen("menci_game.out","w",stdout);
//srand(time(0));
scanf("%d%d",&n,&m);
root=1;
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w),addedge(v,u,w);
}
dfs1(1,1,1,0),dfs2(1,1);
build(1,1,n);
//printf("%lld\n",minx[1]);
for (int i=1;i<=m;i++)
{
int opt,u,v,a,b;
scanf("%d%d%d",&opt,&u,&v);
if (opt==1)
{
scanf("%d%d",&a,&b);
treechange(u,v,a,b);
}
else printf("%lld\n",treeask(u,v));
}
return 0;
}