其他分享
首页 > 其他分享> > [SDOI2016]游戏

[SDOI2016]游戏

作者:互联网

description

一个长为\(n\)的数列,每个初始为123456789123456789。
操作:
0 s t a b:s到t的链上每个点x跟dist(s,x)*a+b取min。
1 s t:求s到t的链上的min。

solution

李超+树链剖分
关键是想好树链剖分的李超线段树下标维护的是什么(x的范围)。
显然一条链dfn从小到大,dis也是从小到大。即维护的是[dis[x],dis[y]]。但实际上为了下标区间的连续性,线段树节点表示的为[dfn[x],dfn[y]]
不过知道dfs序推出远节点的dis不难。
知道这个这道题就能做出来了。

code

点击查看代码
//wr1: 哭,我柿子推错了,我看我有20pt就排除了这种可能qaq…… 
//wr2: 某处提前算了F(id,l/r)但后面id会变,却直接拿去用。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+5;
const ll inf=123456789123456789ll;
struct _line{
	ll k,b;
}L[N];
int n,m,ltot;
int nxt[N],to[N],head[N],ecnt,dfn[N],In[N];
ll dis[N],len[N];
void add_edge(int u,int v,int w) {nxt[++ecnt]=head[u];to[ecnt]=v;len[ecnt]=w;head[u]=ecnt;}
int top[N],Time,son[N],sz[N],dep[N],fa[N],ed[N];
void gt_son(int u) {
	sz[u]=1;
	for(int i=head[u];i;i=nxt[i]) {
		int v=to[i];if(v==fa[u])continue;
		fa[v]=u;dis[v]=dis[u]+len[i];dep[v]=dep[u]+1;
		gt_son(v);
		if(sz[v]>sz[son[u]]) {son[u]=v;}
		sz[u]+=sz[v];
	}
}
void gt_top(int u,int Tp) {
	top[u]=Tp;
	dfn[++Time]=u;In[u]=ed[Tp]=Time;
	if(son[u])gt_top(son[u],Tp);
	for(int i=head[u];i;i=nxt[i]) {
		int v=to[i];if(v==fa[u]||v==son[u])continue;
		gt_top(v,v);
	}
}
int bst[N<<2],ls[N<<2],rs[N<<2],nd,rt[N];
ll mn[N<<2];
struct node {int l,r;ll _l,_r;}T[N<<2];
ll F(int p,ll X) {return L[p].k*X+L[p].b;}
void Build(int &x,int l,int r) {
	x=++nd;T[x]=(node){l,r,dis[dfn[l]],dis[dfn[r]]};mn[x]=inf;
	if(l==r)return;
	int mid=(l+r)>>1;
	Build(ls[x],l,mid);Build(rs[x],mid+1,r);
}
void Update(int x,int l,int r,int id) {
	if(T[x].l==T[x].r) {
		ll _y=T[x]._l;
		if(!bst[x]) {bst[x]=id;mn[x]=F(id,_y);return;}
		ll w=F(id,_y);
		if(F(bst[x],_y)>w) {bst[x]=id;mn[x]=w;}
		return;
	}
	int mid=(T[x].l+T[x].r)>>1;
	if(l<=T[x].l&&T[x].r<=r) {
		ll _l(T[x]._l),_r(T[x]._r),_m(dis[dfn[mid]]);
		if(!bst[x]) {bst[x]=id;mn[x]=min(mn[x],min(F(id,_l),F(id,_r)));return;}
		if(F(bst[x],_m)>F(id,_m)) {swap(bst[x],id);}
		if(F(bst[x],_l)>F(id,_l)) {Update(ls[x],l,r,id);}
		if(F(bst[x],_r)>F(id,_r)) {Update(rs[x],l,r,id);}
		mn[x]=min(min(F(bst[x],_l),F(bst[x],_r)),min(mn[ls[x]],mn[rs[x]]));
		return;
	}
	if(l<=mid) Update(ls[x],l,r,id);
	if(r>mid) Update(rs[x],l,r,id);
	mn[x]=min(mn[x],min(mn[ls[x]],mn[rs[x]]));
}
ll kl,kr;
ll Ask(int x,int l,int r) {
//	if(!x)printf("!");
	if(l<=T[x].l&&T[x].r<=r){return mn[x];}
	int mid=(T[x].l+T[x].r)>>1;
	ll res=!bst[x]?inf:min(F(bst[x],max(T[x]._l,kl)),F(bst[x],min(T[x]._r,kr)));
	if(l<=mid) {res=min(res,Ask(ls[x],l,r));}
	if(r>mid) {res=min(res,Ask(rs[x],l,r));}
	return res;
}
int Lca(int x,int y) {
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		x=fa[top[x]];
	}
	return dep[x]<=dep[y]?x:y;
}
void Update1(int x,int c,int id) {
	while(top[x]!=top[c]) {
		int tp(top[x]);
		Update(rt[tp],In[tp],In[x],id);
		x=fa[tp];
	}
	Update(rt[top[x]],In[c],In[x],id);
}
ll Query(int x,int y) {
	ll res=inf;
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		int tp(top[x]);
		kl=dis[tp];kr=dis[x];
		res=min(res,Ask(rt[tp],In[tp],In[x]));
		x=fa[tp];
	}
	if(dep[x]>dep[y])swap(x,y);
	kl=dis[x],kr=dis[y];
	res=min(res,Ask(rt[top[x]],In[x],In[y]));
	return res;
}
void init_tree() {
	gt_son(1);gt_top(1,1);
	for(int l=1,r;l<=n;l=r+1) {
		r=ed[dfn[l]];
		Build(rt[dfn[l]],l,r);
	}
}
void in_puts() {
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++) {int u,v,w;scanf("%d%d%d",&u,&v,&w);add_edge(u,v,w);add_edge(v,u,w);}
}
void solve() {
	L[0].b=inf;
	mn[0]=inf;
	for(int i=1;i<=m;i++) {
		int op,s,t;ll a,b;
		scanf("%d%d%d",&op,&s,&t);
//		printf("%d:~~~~~~~~~~~~~~~\n",i);
		if(op==1) {
			scanf("%lld%lld",&a,&b);
			int c=Lca(s,t);
			L[++ltot]=(_line){-a,a*dis[s]+b}; Update1(s,c,ltot);
			L[++ltot]=(_line){a,a*(dis[s]-2*dis[c])+b}; Update1(t,c,ltot);
		}
		else {
			printf("%lld\n",Query(s,t));
		}
		
	}
}
int main() {
	in_puts();
	init_tree();
	solve();
	return 0; 
}

标签:ll,游戏,min,int,top,bst,SDOI2016,id
来源: https://www.cnblogs.com/bestime/p/16186590.html