[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