[bzoj4515] [SDOI2016]游戏

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;
}
posted @ 2019-01-10 19:15  Hyscere  阅读(309)  评论(0编辑  收藏  举报