[bzoj4515] [SDOI2016]遊戲
阿新 • • 發佈:2019-01-10
Description
Alice 和 Bob 在玩一個遊戲。
遊戲在一棵有 n 個點的樹上進行。最初,每個點上都只有一個數字,那個數字是 123456789123456789。
有時,Alice 會選擇一條從 s 到 t 的路徑,在這條路徑上的每一個點上都新增一個數字。對於路徑上的一個點 r,
若 r 與 s 的距離是 dis,那麼 Alice 在點 r 上新增的數字是 a×dis+b。有時,Bob 會選擇一條從 s 到 t 的路徑。
他需要先從這條路徑上選擇一個點,再從那個點上選擇一個數字。
Bob 選擇的數字越小越好,但大量的數字讓 Bob 眼花繚亂。Bob 需要你幫他找出他能夠選擇的最小的數字。
Input
第一行兩個數字 n、m,表示樹的點數和進行的運算元。
接下來 n−1 行,每行三個數字 u、v、w,表示樹上有一條連線 u、v 的邊,長度是 w。
接下來 m 行。每行第一個數字是 1 或 2。
若第一個數是 1,表示 Alice 進行操作,接下來四個數字 s、t、a、b。
若第一個數是 2,表示 Bob 進行操作,接下來四個數字 s、t。
Output
每當 Bob 進行操作,輸出一行一個數,表示他能夠選擇的最小的數字
Sample Input
3 5
1 2 10
2 3 20
2 1 3
1 2 3 5 6
2 2 3
1 2 3 -5 -6
2 2 3
Sample Output
123456789123456789
6
-106
Solution
對於一次修改\((s,t,a,b)\),可以分為兩部分:
- \(s\)到\(lca\),對於鏈上的\(x\),新加的值為\(a\cdot(dis[s]-dis[x])+b\),其中\(dis[x]\)為\(1\)到\(x\)的距離。可以發現這玩意是一個關於\(dis[x]\)的一次函式,設函式為\(y=kx+b\)的話,那麼\(k=-a,b=a \cdot dis[s]+b\),所以可以用一個樹剖加李超線段樹來維護,李超線段樹模板題——[HEOI2013]Segment。
- \(t\)到\(lca\),同樣的,值為\(a\cdot (dis[x]+dis[s]-2\cdot dis[lca])+b\)
#include<bits/stdc++.h>
using namespace std;
#define int long long
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
const int maxn = 3e5+10;
const int inf = 123456789123456789;
int n,m,dis[maxn],re[maxn];
struct data {
int l,r,k,b;
int calc(int x) {return k*x+b;}
};
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)>>1)
struct Segment_Tree {
data t[maxn<<2];
int mn[maxn<<2];
void update(int p) {mn[p]=min(mn[p],min(mn[ls],mn[rs]));}
void cover(int p,int l,int r,data s) {
int lt=t[p].calc(dis[re[l]]),rt=t[p].calc(dis[re[r]]);
int lp=s.calc(dis[re[l]]),rp=s.calc(dis[re[r]]);
if(lp>=lt&&rp>=rt) return ;
if(lp<=lt&&rp<=rt) {t[p]=s;mn[p]=min(min(lp,rp),mn[p]);return ;}
double po=1.0*(t[p].b-s.b)/(1.0*(s.k-t[p].k));
if(lp>lt) {
if(po<=(double)dis[re[mid]]) cover(ls,l,mid,t[p]),t[p]=s;
else cover(rs,mid+1,r,s);
} else {
if(po<=(double)dis[re[mid]]) cover(ls,l,mid,s);
else cover(rs,mid+1,r,t[p]),t[p]=s;
}
mn[p]=min(min(lp,rp),mn[p]),update(p);
}
void modify(int p,int l,int r,data s) {
if(s.l<=l&&r<=s.r) return cover(p,l,r,s),void();
if(s.l<=mid) modify(ls,l,mid,s);
if(s.r>mid) modify(rs,mid+1,r,s);
update(p);
}
int query(int p,int l,int r,int x,int y) {
if(x<=l&&r<=y) return mn[p];
int ans=min(t[p].calc(dis[re[max(x,l)]]),t[p].calc(dis[re[min(r,y)]]));
if(t[p].b==inf) ans=inf;
if(x<=mid) ans=min(ans,query(ls,l,mid,x,y));
if(y>mid) ans=min(ans,query(rs,mid+1,r,x,y));
return ans;
}
void build(int p,int l,int r) {
t[p]=(data){l,r,0,inf};mn[p]=inf;
if(l==r) return ;
build(ls,l,mid),build(rs,mid+1,r);
}
}SGT;
struct Heavy_Light_Decomposation {
int head[maxn],tot,dfn[maxn],hs[maxn],top[maxn],sz[maxn],dfn_cnt,dep[maxn],f[maxn];
struct edge{int to,nxt,w;}e[maxn<<1];
void add(int u,int v,int w) {e[++tot]=(edge){v,head[u],w},head[u]=tot;}
void ins(int u,int v,int w) {add(u,v,w),add(v,u,w);}
void dfs(int x,int fa) {
f[x]=fa,dep[x]=dep[fa]+1,sz[x]=1;
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa) {
dis[e[i].to]=dis[x]+e[i].w;
dfs(e[i].to,x);
sz[x]+=sz[e[i].to];
if(sz[hs[x]]<sz[e[i].to]) hs[x]=e[i].to;
}
}
void dfs2(int x) {
if(hs[f[x]]==x) top[x]=top[f[x]];
else top[x]=x;
dfn[x]=++dfn_cnt;re[dfn_cnt]=x;
if(hs[x]) dfs2(hs[x]);
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=f[x]&&e[i].to!=hs[x]) dfs2(e[i].to);
}
int lca(int x,int y) {
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=f[top[x]];
}if(dep[x]>dep[y]) swap(x,y);return x;
}
int query(int x,int y) {
int ans=inf;
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans=min(ans,SGT.query(1,1,n,dfn[top[x]],dfn[x]));
x=f[top[x]];
}if(dep[x]>dep[y]) swap(x,y);
ans=min(ans,SGT.query(1,1,n,dfn[x],dfn[y]));
return ans;
}
void modify(int x,int t,int k,int b) {
while(top[x]!=top[t]) {
SGT.modify(1,1,n,(data){dfn[top[x]],dfn[x],k,b});
x=f[top[x]];
}SGT.modify(1,1,n,(data){dfn[t],dfn[x],k,b});
}
// y= a*dis+b
void solve(int s,int t,int a,int b) {
int l=lca(s,t);
// y=a*dis+b=a*(dis[s]-dis[x])+b -> k=-a,b=a*dis[s]+b
modify(s,l,-a,a*dis[s]+b);
// y=a*dis+b=a*(dis[x]+dis[s]-2*dis[l])+b -> k=a,b=a*(dis[s]-2*dis[l])+b
modify(t,l,a,a*(dis[s]-2*dis[l])+b);
}
}HLD;
signed main() {
read(n),read(m);
for(int i=1,x,y,z;i<n;i++) read(x),read(y),read(z),HLD.ins(x,y,z);
HLD.dfs(1,0),HLD.dfs2(1),SGT.build(1,1,n);
for(int i=1;i<=m;i++) {
int op,s,t,a,b;
read(op),read(s),read(t);
if(op==1) read(a),read(b),HLD.solve(s,t,a,b);
else write(HLD.query(s,t));
}
return 0;
}