SDOI2016游戏


每次修改可以看成是一个一次函数,分成两个点到(lca)分别修改

于是树链剖分+李超线段树+标记永久化求最小值

时间复杂度(O(nlog_n^3)),但出题人良心可以过

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f==1?x:-x;
}
const int N=1e5+4,inf=123456789123456789ll;
#define lc (p<<1)
#define rc (p<<1|1)
int n,m,tim;
int dis[N],dep[N],siz[N],son[N],fa[N],pos[N],dfn[N],top[N];
int tk[N<<2],tb[N<<2],mn[N<<2],lx[N<<2],rx[N<<2],mx[N<<2];
void build(int p,int l,int r){
	tb[p]=mn[p]=inf;
	lx[p]=dis[pos[l]];rx[p]=dis[pos[r]];
	int mid=l+r>>1;
	mx[p]=dis[pos[mid]];
	if(l==r)return;
	build(lc,l,mid);build(rc,mid+1,r);
}
void modify(int p,int l,int r,int ql,int qr,int k,int b){
	int mid=l+r>>1;
	if(ql<=l&&r<=qr){
		int l1=k*lx[p]+b,r1=k*rx[p]+b,l2=tk[p]*lx[p]+tb[p],r2=tk[p]*rx[p]+tb[p];
		if(l1>=l2&&r1>=r2)return;
		if(l1<l2&&r1<r2){
			tk[p]=k;tb[p]=b;
			mn[p]=min(mn[p],min(l1,r1));
			return;
		}
		double x=(double)(b-tb[p])/(tk[p]-k);
		if(l1>l2){
			if(x<=mx[p]){
				modify(lc,l,mid,ql,qr,tk[p],tb[p]);
				tk[p]=k;tb[p]=b;
			}
			else modify(rc,mid+1,r,ql,qr,k,b);
		}
		else{
			if(x<=mx[p])modify(lc,l,mid,ql,qr,k,b);
			else{
				modify(rc,mid+1,r,ql,qr,tk[p],tb[p]);
				tk[p]=k;tb[p]=b;
			}
		}
		mn[p]=min(mn[p],min(l1,r1));
		return;
	}
	if(ql<=mid)modify(lc,l,mid,ql,qr,k,b);
	if(mid<qr)modify(rc,mid+1,r,ql,qr,k,b);
	mn[p]=min(mn[p],min(mn[lc],mn[rc]));
}
inline int query(int p,int l,int r,int ql,int qr){
	if(ql<=l&&r<=qr)return mn[p];
	int mid=l+r>>1,xl=max(l,ql),xr=min(r,qr);
	int ret=min(dis[pos[xl]]*tk[p],dis[pos[xr]]*tk[p])+tb[p];
	if(ql<=mid)ret=min(ret,query(lc,l,mid,ql,qr));
	if(mid<qr)ret=min(ret,query(rc,mid+1,r,ql,qr));
	return ret; 
}
struct edge{
	int v,w,nxt;
}e[N<<1];
int first[N],cnt=0;
inline void add(int u,int v,int w){
	e[++cnt]=(edge){v,w,first[u]};
	first[u]=cnt;
}
void dfs_1(int x){
	dep[x]=dep[fa[x]]+1;
	siz[x]=1;
	for(int i=first[x],v;i;i=e[i].nxt){
		v=e[i].v;
		if(v==fa[x])continue;
		fa[v]=x;
		dis[v]=dis[x]+e[i].w;
		dfs_1(v);
		siz[x]+=siz[v];
		if(siz[v]>siz[son[x]])son[x]=v;
	}
}
void dfs_2(int x,int tp){
	top[x]=tp;
	dfn[x]=++tim;
	pos[tim]=x;
	if(son[x]){
		dfs_2(son[x],tp);
	}
	for(int i=first[x],v;i;i=e[i].nxt){
		v=e[i].v;
		if(v==son[x]||v==fa[x])continue;
		dfs_2(v,v);
	}
}
inline int LCA(int u,int v){
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]])u^=v^=u^=v;
		u=fa[top[u]];
	}
	return dep[u]<dep[v]?u:v;
}
inline int query(int u,int v){
	int ret=inf;
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]])u^=v^=u^=v;
		ret=min(ret,query(1,1,n,dfn[top[u]],dfn[u]));
		u=fa[top[u]];
	}
	if(dep[u]>dep[v])u^=v^=u^=v;
	return min(ret,query(1,1,n,dfn[u],dfn[v]));
}
inline void modify(int u,int v,int k,int b){
	while(top[u]!=top[v]){
		modify(1,1,n,dfn[top[u]],dfn[u],k,b);
		u=fa[top[u]];
	}
	modify(1,1,n,dfn[v],dfn[u],k,b);
}
signed main(){
	n=read();m=read();
	for(int i=1,u,v,w;i<n;i++){
		u=read();v=read();w=read();
		add(u,v,w);add(v,u,w);
	}
	dfs_1(1);
	dfs_2(1,1);
	build(1,1,n); 
	while(m--){
		static int op,u,v,x,y,w;
		op=read();u=read();v=read();
		if(op==2){cout<<query(u,v)<<"
";continue;}
		x=read();y=read();
		w=LCA(u,v);
		modify(u,w,-x,x*dis[u]+y);
		modify(v,w,x,x*(dis[u]-dis[w]*2)+y);
	}
	return (0-0);
}
原文地址:https://www.cnblogs.com/aurora2004/p/12559760.html