树链剖分 区间维护 直线 相交的话判下怎么传即可。。
注意相交上下取整问题 以及一系列long long
我求线段端点 写成了 b*x+b真是愚蠢至极
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define LL long long
using namespace std;
const int N=100010;
const LL INF=123456789123456789LL;
struct Edge{
int next,v;
LL w;
}e[N*2];
int first[N],size[N],fa[N],num,ti,m,
de[N],dfn[N],id[N],belong[N],n;
LL dis[N],mn[N*4],A[N*4],B[N*4];
bool hastag[N*4];
void add(int u,int v,LL w){
e[++num].next=first[u];e[num].w=w;
first[u]=num;e[num].v=v;
}
void dfs(int x){
size[x]=1;
for(int i=first[x];i;i=e[i].next){
int v=e[i].v;if(de[v]) continue;
dis[v]=dis[x]+e[i].w;de[v]=de[x]+1;
fa[v]=x;dfs(v);size[x]+=size[v];
}
}
void dfs(int x,int chain){
dfn[x]=++ti;id[ti]=x;
belong[x]=chain;int k=0;
for(int i=first[x];i;i=e[i].next){
int v=e[i].v;
if(de[v]<de[x]) continue;
if(size[v]>size[k]) k=v;
}
if(!k) return;dfs(k,chain);
for(int i=first[x];i;i=e[i].next){
int v=e[i].v;
if(de[v]<de[x]||k==v) continue;
dfs(v,v);
}
}
int Lca(int u,int v){
while(belong[u]!=belong[v]){
if(de[belong[u]]<de[belong[v]]) swap(u,v);
u=fa[belong[u]];
}
return de[u]<de[v]?u:v;
}
void update(int x,int l,int r){
if(hastag[x]) mn[x]=min(A[x]*dis[id[l]],A[x]*dis[id[r]])+B[x];
if(l!=r) mn[x]=min(mn[x],min(mn[2*x],mn[2*x+1]));
}
void Add2(int x,int l,int r,LL a,LL b){
if(!hastag[x]){
hastag[x]=1;A[x]=a;B[x]=b;update(x,l,r);return;
}
int mid=(l+r)>>1;
LL x1=A[x]*dis[id[l]]+B[x],y1=A[x]*dis[id[r]]+B[x],
x2=a*dis[id[l]]+b,y2=a*dis[id[r]]+b;
//cout<<x<<" "<<l<<" "<<r<<" "<<a<<" "<<b<<" ";cout<<x1<<" "<<y1<<" "<<x2<<" "<<y2<<endl;
if(x2<=x1&&y2<=y1) {A[x]=a;B[x]=b;}
else if(x2>=x1&&y2>=y1)return;
else if(a<A[x]){
LL tmp=(b-B[x])/(A[x]-a)+1;
if(tmp<=dis[id[mid]]){
swap(a,A[x]);swap(b,B[x]);
Add2(2*x,l,mid,a,b);
}
else Add2(2*x+1,mid+1,r,a,b);
}
else {
// if(a==A[x]) cout<<x1<<" "<<x2<<" "<<y1<<" "<<y2<<endl;
LL tmp=(b-B[x]-1)/(A[x]-a);
if(tmp>dis[id[mid]]){
swap(A[x],a);swap(B[x],b);
Add2(2*x+1,mid+1,r,a,b);
}
else Add2(2*x,l,mid,a,b);
}
update(x,l,r);
}
void Add1(int x,int l,int r,int _l,int _r,LL a,LL b){
if(_l<=l&&r<=_r){
Add2(x,l,r,a,b);
}
else {
int mid=(l+r)>>1;
if(_l<=mid) Add1(2*x,l,mid,_l,_r,a,b);
if(_r>mid) Add1(2*x+1,mid+1,r,_l,_r,a,b);
}
update(x,l,r);
}
void Tree_Add2(int s,int t,LL a,LL b){
while(belong[s]!=belong[t]){
int pnt=belong[s];
Add1(1,1,n,dfn[pnt],dfn[s],a,b);
s=fa[belong[s]];
}
// cout<<dfn[t]<<" "<<dfn[s]<<" "<<s<<" "<<t<<"!!!"<<endl;
Add1(1,1,n,dfn[t],dfn[s],a,b);
}
void Tree_Add1(int s,int t,LL a,LL b){
int lc=Lca(s,t);
Tree_Add2(s,lc,-a,b+a*dis[s]);
Tree_Add2(t,lc,a,b+a*(dis[s]-2*dis[lc]));
}
LL Ask(int x,int l,int r,int _l,int _r){
if(_l<=l&&r<=_r) return mn[x];
LL res=mn[0];
if(hastag[x]) {
int ll=max(_l,l),rr=min(_r,r);
res=min(res,min(A[x]*dis[id[ll]],A[x]*dis[id[rr]])+B[x]);
}
int mid=(l+r)>>1;
if(_l<=mid) res=min(res,Ask(2*x,l,mid,_l,_r));
if(_r>mid) res=min(res,Ask(2*x+1,mid+1,r,_l,_r));
return res;
}
LL Tree_Ask2(int s,int t){
LL res=mn[0];
while(belong[s]!=belong[t]){
res=min(res,Ask(1,1,n,dfn[belong[s]],dfn[s]));
s=fa[belong[s]];
}
return min(res,Ask(1,1,n,dfn[t],dfn[s]));
}
LL Tree_Ask1(int s,int t){
int lc=Lca(s,t);
return min(Tree_Ask2(s,lc),Tree_Ask2(t,lc));
}
void print(int x,int l,int r){
cout<<x<<" "<<l<<" "<<r<<" "<<A[x]<<" "<<B[x]<<" "<<mn[x]<<endl;
if(l==r) return;
int mid=(l+r)>>1;
print(2*x,l,mid);
print(2*x+1,mid+1,r);
}
int read(){
int x=0,fu=1; char ch=getchar();
while (ch<'0' || ch>'9'){ if (ch=='-') fu=-1; ch=getchar(); }
while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
return x*fu;
}
int main(){
n=read(),m=read();
//scanf("%d%d",&n,&m);
LL w;
for(int i=1,a,b;i<n;i++){
a=read();b=read();w=read();
add(a,b,w);add(b,a,w);
}de[1]=1;
dfs(1);dfs(1,1);
// for(int i=1;i<=n;i++)
// cout<<dfn[i]<<" "<<belong[i]<<endl;
//cout<<"!"<<endl;
int k=0;
for(int i=0;i<=4*n;i++) mn[i]=INF;
int Type,s,t;LL a,b;
while(m--){
Type=read();
//scanf("%d",&Type);
if(Type==1){
s=read();t=read();a=read();b=read();
// scanf("%d%d%lld%lld",&s,&t,&a,&b);
Tree_Add1(s,t,a,b);
}
else {
k++;
s=read();t=read();
// scanf("%d%d",&s,&t);
//cout<<s<<" "<<t<<" "<<Lca(s,t)<<endl;
printf("%lld\n",Tree_Ask1(s,t));
Tree_Ask1(s,t);
//if(k==134) print(1,1,n);
}
}
return 0;
}