数据结构题就不提示了……
本题很明显的一个思路就是用树剖维护信息 , 对于每一段我们这样记录一个标记: Axi+b , 对于这一段中的每一个节点 p , Xp 等于到这一段开头节点的距离。
那么一个重要的问题来啦。 如何下传一个标记呢?如果你做过一道用线段树维护半平面交的题目的话 , 此时的思路就是显然的。 我们假设此时这条线段上躺着一个标记 a1x+b1 现在我们要加一个标记 a2x+b2 。 显然 , 我们只能留一个 , 那么我们要知道哪一个更优。让我们来解不等式:
此时绿色部分第一个标记更优 , 红色部分第二个标记更优 , 那么我们就应该把第一个标记推下去 , 因为它完全被包含在 [L,Mid] 中。
吐槽: RE不止 ,最后发现是爆栈??链状结构我就不多写判断了 , 鉴于出题人习惯于把 i 连向 i−1 我就顺其自然好了
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#include <vector>
#include <deque>
#include <set>
#include <map>
#include <complex>
#include <climits>
#include <cassert>
using namespace std;
typedef long long ll;
const int maxn = 1e5+1e2;
const ll INF = 123456789123456789;
struct edge{ int t; ll v; edge(int t=0 , ll v=0):t(t),v(v){} };
int n , m , dfsCnt;
vector<edge> g[maxn];
ll dis[maxn];
int fa[maxn] , Size[maxn] , dep[maxn] , bl[maxn] , id[maxn] , reid[maxn];
void dfs(int x)
{
Size[x] = 1;
for(int i=0;i<g[x].size();i++)
{
edge& e = g[x][i];
if(e.t == fa[x]) continue;
fa[e.t] = x;
dep[e.t] = dep[x] + 1;
dis[e.t] = dis[x] + e.v;
dfs(e.t);
Size[x] += Size[e.t];
}
}
void dfs(int x , int num)
{
id[x] = ++dfsCnt;
reid[dfsCnt] = x;
bl[x] = num;
int mx =0 , w;
for(int i=0;i<g[x].size();i++)
{
edge& e = g[x][i];
if(e.t == fa[x]) continue;
if(mx < Size[e.t]) mx = Size[w = e.t];
}
if(mx) dfs(w , num);
for(int i=0;i<g[x].size();i++)
{
edge& e = g[x][i];
if(e.t == fa[x] || e.t == w) continue;
dfs(e.t , e.t);
}
}
bool flag[maxn*10];
ll mn[maxn*10] , A[maxn*10] , B[maxn*10];
int lca(int x , int y)
{
while(bl[x] != bl[y])
{
if(dep[bl[x]] > dep[bl[y]]) swap(x , y);
y = fa[bl[y]];
}
return dep[x] < dep[y] ? x : y;
}
void maintain(int o , int l , int r)
{
if(flag[o]) mn[o] = min(B[o] , A[o]*(dis[reid[r]] - dis[reid[l]])+B[o]);
if(l!=r) mn[o] = min(mn[o] , min(mn[o*2] , mn[o*2+1]));
}
void giveFlag(int o , int l , int r , ll a , ll b)
{
if(!flag[o]) A[o] = a , B[o] = b , flag[o] = 1;
else
{
if(A[o] == a || l == r) B[o] = min(B[o] , b);
else
{
int mid = (l+r)/2; ll d , len = dis[reid[mid+1]] - dis[reid[l]];
if(A[o] < a && B[o] < b) ;
else if(A[o] > a && B[o] > b) swap(A[o] , a) , swap(B[o] , b);
else if(A[o] > a && B[o] < b)
{
d = (b - B[o])/(A[o] - a);
if(d <= len)
{
swap(A[o] , a) , swap(B[o] , b);
giveFlag(o*2 , l , mid , a , b);
}
else giveFlag(o*2+1 , mid+1 , r , a , b+a*len);
}
else if(A[o] < a && B[o] > b)
{
d = (B[o] - b + a - A[o] - 1)/(a - A[o]);
if(d <= len) giveFlag(o*2 , l , mid , a , b);
else
{
swap(A[o] , a) , swap(B[o] , b);
giveFlag(o*2+1 , mid+1 , r , a , b+a*len);
}
}
}
}
maintain(o , l , r);
}
void modify(int o , int l , int r , int L , int R , ll a , ll b)
{
if(L <= l && r <= R) giveFlag(o, l, r, a, b+a*(dis[reid[l]]-dis[reid[L]]));
else
{
int mid = (l+r)/2;
if(L <= mid) modify(o*2, l, mid, L, R, a, b);
if(R > mid) modify(o*2+1, mid+1, r, L, R, a, b);
}
maintain(o, l, r);
}
void modify2(int l , int x , ll a , ll b)
{
int f;
while(bl[x] != bl[l])
{
f = bl[x];
modify(1 , 1 , n , id[f] , id[x] , a , a*(dis[f]-dis[l])+b);
x = fa[f];
}
modify(1 , 1 , n , id[l] , id[x] , a , b);
}
void modify(int x , int y , ll a , ll b)
{
int l = lca(x , y);
modify2(l , x , -a , b+a*(dis[x]-dis[l]));
modify2(l , y , a , b+a*(dis[x]-dis[l]));
}
ll query(int o , int l , int r , int L , int R)
{
ll res = INF;
if(flag[o])
{
int ll = max(l, L);
int rr = min(r, R);
res = min(A[o]*(dis[reid[ll]]-dis[reid[l]]) , A[o]*(dis[reid[rr]]-dis[reid[l]])) + B[o];
}
if(L <= l && r <= R) return min(res, mn[o]);
else
{
int mid = (l+r)/2;
if(L <= mid) res = min(res , query(o*2, l, mid, L, R));
if(R > mid) res = min(res , query(o*2+1, mid+1, r, L, R));
return res;
}
}
ll query(int x , int y)
{
ll res = INF;
while(bl[x] != bl[y])
{
if(dep[bl[x]] > dep[bl[y]]) swap(x, y);
res = min(res , query(1, 1, n, id[bl[y]], id[y]));
y = fa[bl[y]];
}
if(dep[x] > dep[y]) swap(x, y);
return min(res, query(1, 1, n, id[x], id[y]));
}
int main()
{
cin>>n>>m;
bool line = true;
for(int i=1;i<n;i++)
{
int a , b; ll c;
scanf("%d%d%lld" , &a , &b , &c);
g[a].push_back(edge(b , c));
g[b].push_back(edge(a , c));
if(b != a+1) line = false;
}
if(line)
{
for(int i=1;i<=n;i++)
{
fa[i] = i-1; Size[i] = n+1-i; dep[i] = i; id[i] = reid[i] = i; bl[i] = 1;
for(int j=0;j<g[i].size();j++) if(g[i][j].t == i-1) dis[i] = dis[i-1]+g[i][j].v;
}
}
else
dfs(1),
dfs(1 , 1);
for(int i=0;i<maxn*10;i++) mn[i] = INF;
int op , s , t; ll a , b;
while(m--)
{
scanf("%d" , &op);
if(op == 1)
{
scanf("%d%d%lld%lld" , &s , &t , &a , &b);
modify(s, t, a, b);
}
else
{
scanf("%d%d" , &s , &t);
printf("%lld\n" , query(s, t));
}
}
return 0;
}