LGP4069口胡

感觉怪怪的(?)

题意有点儿类似给区间加上一个一次函数,然后询问一个区间的最值。

不妨来考虑一下一次函数具有单调性。对于一个询问区间,被一个一次函数完全包含时,这个一次函数的极值只有可能是这个区间的左端点或者右端点。

对于非链顶部分,查询相当于前缀查询。如果我们只在这个一次函数的端点上加上权值,那么只会漏掉一种情况:一次函数的右端点在询问区间的右端点的右边。直接进行一个单点查询就可以了。

链顶部分有亿点点麻烦,是区间查询。和上面如法炮制就可以了。

#include<cstdio>
typedef long long ll;
const int M=1e5+5;const ll INF=123456789123456789ll;
int n,m,dfc,cnt,h[M],f[M],d[M],dfn[M],siz[M],son[M],top[M];
ll mi[M<<2];ll S[M],sum[M];
inline ll min(const ll&a,const ll&b){
	return a>b?b:a;
}
struct Edge{
	int v,w,nx;
}e[M<<1];
inline void Add(const int&u,const int&v,const int&w){
	e[++cnt]=(Edge){v,w,h[u]};h[u]=cnt;
	e[++cnt]=(Edge){u,w,h[v]};h[v]=cnt;
}
struct line{
	int k;ll b;
	line(const int&k=0,const ll&b=0):k(k),b(b){}
	inline ll operator()(const ll&x)const{
		return 1ll*k*x+b;
	}
}l[M<<2];
inline void swap(line&a,line&b){
	line c=a;a=b;b=c;
}
inline void DFS1(const int&u){
	d[u]=d[f[u]]+1;siz[u]=1;
	for(int v,E=h[u];E;E=e[E].nx)if((v=e[E].v)^f[u]){
		f[v]=u;S[v]=S[u]+e[E].w;DFS1(v);siz[u]+=siz[v];if(siz[v]>siz[son[u]])son[u]=v;
	}
}
inline void DFS2(const int&u,const int&tp){
	top[u]=tp;dfn[u]=++dfc;sum[dfc]=sum[dfc-1]+S[u]-S[f[u]];if(!son[u])return;DFS2(son[u],tp);
	for(int E=h[u];E;E=e[E].nx)if(e[E].v^f[u]&&e[E].v^son[u])DFS2(e[E].v,e[E].v);
}
inline int LCA(int u,int v){
	while(top[u]^top[v])d[top[u]]>d[top[v]]?u=f[top[u]]:v=f[top[v]];return d[u]>d[v]?v:u;
}
inline ll dis(const int&u,const int&v){
	return S[u]+S[v]-(S[LCA(u,v)]<<1);
}
inline void Build(const int&u,const int&L=1,const int&R=n){
	mi[u]=l[u].b=INF;if(L==R)return;const int&mid=L+R>>1;Build(u<<1,L,mid);Build(u<<1|1,mid+1,R);
}
inline void push(const int&u,line P,const int&L=1,const int&R=n){
	const int&mid=L+R>>1;if(l[u].b==INF||P(sum[mid])<=l[u](sum[mid]))swap(l[u],P);
	if(P(sum[L])>=l[u](sum[L])&&P(sum[R])>=l[u](sum[R]))return;
	if(L<R){
		if(P(sum[L])<l[u](sum[L]))push(u<<1,P,L,mid);
		else if(P(sum[R])<l[u](sum[R]))push(u<<1|1,P,mid+1,R);
	}
}
inline void update(const int&u,const line&P,const int&l,const int&r,const int&L=1,const int&R=n){
	if(l>R||L>r)return;if(l<=L&&R<=r)return push(u,P,L,R);
	const int&mid=L+R>>1;update(u<<1,P,l,r,L,mid);update(u<<1|1,P,l,r,mid+1,R);
}
inline void Add(const int&u,const int&x,const ll&V,const int&L=1,const int&R=n){
	mi[u]=min(mi[u],V);if(L==R)return;
	const int&mid=L+R>>1;x<=mid?Add(u<<1,x,V,L,mid):Add(u<<1|1,x,V,mid+1,R);
}
inline ll Qry(const int&u,const int&x,const int&L=1,const int&R=n){
	if(L==R)return l[u](sum[x]);
	const int&mid=L+R>>1;return min(x<=mid?Qry(u<<1,x,L,mid):Qry(u<<1|1,x,mid+1,R),l[u](sum[x]));
}
inline ll Qmi(const int&u,const int&l,const int&r,const int&L=1,const int&R=n){
	if(l>R||L>r)return INF;if(l<=L&&R<=r)return mi[u];
	const int&mid=L+R>>1;return min(Qmi(u<<1,l,r,L,mid),Qmi(u<<1|1,l,r,mid+1,R));
}
inline void modify(int u,int v,line P){
	const int w=u;
	while(top[u]^top[v]){
		if(d[top[u]]>d[top[v]]){
			const line F(-P.k,P.b+1ll*P.k*(dis(w,top[u])+sum[dfn[top[u]]]));
			update(1,F,dfn[top[u]],dfn[u]);Add(1,dfn[top[u]],F(sum[dfn[top[u]]]));Add(1,dfn[u],F(sum[dfn[u]]));
			u=f[top[u]];
		}
		else{
			const line F(P.k,P.b+1ll*P.k*(dis(w,top[v])-sum[dfn[top[v]]]));
			update(1,F,dfn[top[v]],dfn[v]);Add(1,dfn[top[v]],F(sum[dfn[top[v]]]));Add(1,dfn[v],F(sum[dfn[v]]));
			v=f[top[v]];
		}
	}
	if(d[u]>d[v]){
		const line F(-P.k,P.b+1ll*P.k*(dis(w,v)+sum[dfn[v]]));
		update(1,F,dfn[v],dfn[u]);Add(1,dfn[u],F(sum[dfn[u]]));Add(1,dfn[v],F(sum[dfn[v]]));
	}
	else{
		const line F(P.k,P.b+1ll*P.k*(dis(w,u)-sum[dfn[u]]));
		update(1,F,dfn[u],dfn[v]);Add(1,dfn[u],F(sum[dfn[u]]));Add(1,dfn[v],F(sum[dfn[v]]));
	}
}
inline ll query(int u,int v){
	ll ans(INF);
	while(top[u]^top[v]){
		if(d[top[u]]>d[top[v]]){
			ans=min(ans,min(min(Qry(1,dfn[top[u]]),Qry(1,dfn[u])),Qmi(1,dfn[top[u]],dfn[u])));u=f[top[u]];
		}
		else{
			ans=min(ans,min(min(Qry(1,dfn[top[v]]),Qry(1,dfn[v])),Qmi(1,dfn[top[v]],dfn[v])));v=f[top[v]];
		}
	}
	if(d[u]>d[v])u^=v^=u^=v;
	return min(ans,min(min(Qry(1,dfn[u]),Qry(1,dfn[v])),Qmi(1,dfn[u],dfn[v])));
}
signed main(){
	scanf("%d%d",&n,&m);Build(1);
	for(int u,v,w,i=1;i<n;++i)scanf("%d%d%d",&u,&v,&w),Add(u,v,w);DFS1(1);DFS2(1,1);
	while(m--){
		int opt,s,t;
		scanf("%d%d%d",&opt,&s,&t);
		if(opt==1){
			int x,y;scanf("%d%d",&x,&y);modify(s,t,line(x,y));
		}
		if(opt==2){
			printf("%lld\n",query(s,t));
		}
	}
}
posted @ 2022-04-13 09:06  Prean  阅读(12)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};