bzoj 4515 游戏 Posted on 2019-06-14 | Edited on 2019-06-15 | Views: 树链剖分 + 李超线段树. 显然可以先来一个树剖,就成了区间上的问题.每次修改 $(s,t)$ 就拆成 $(s,lca),(lca,t)$ 两段来做. 于是修改操作都是给一条区间加一条线段的形式,询问是问一个区间内点值的最小值. 用李超线段树维护优势线段与区间的答案即可. 时间复杂度 $O(nlog^3n)$ ,但常数比较小,所以能过. 强行上树系列. 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269#include<bits/stdc++.h>using namespace std;typedef long long ll;inline int read(){ int out=0,fh=1; char jp=getchar(); while ((jp>'9'||jp<'0')&&jp!='-') jp=getchar(); if (jp=='-') fh=-1,jp=getchar(); while (jp>='0'&&jp<='9') out=out*10+jp-'0',jp=getchar(); return out*fh;}const ll inf=123456789123456789;const int MAXN=1e5+10;int ecnt=0,head[MAXN];int to[MAXN<<1],nx[MAXN<<1],val[MAXN<<1];void addedge(int u,int v,int w){ ++ecnt; to[ecnt]=v; nx[ecnt]=head[u]; val[ecnt]=w; head[u]=ecnt;}ll dist[MAXN];int mxson[MAXN],siz[MAXN],fa[MAXN],dep[MAXN];int idx=0,dfn[MAXN],rnk[MAXN],top[MAXN],distofa[MAXN];void dfs1(int u,int Fa){ siz[u]=1; fa[u]=Fa; dep[u]=dep[Fa]+1; for(int i=head[u];i;i=nx[i]) { int v=to[i]; if(v==Fa) continue; distofa[v]=val[i]; dfs1(v,u); siz[u]+=siz[v]; if(siz[v]>siz[mxson[u]]) mxson[u]=v; }}void dfs2(int u,int tp,ll CurDist){ top[u]=tp; dfn[u]=++idx; rnk[idx]=u; dist[idx]=CurDist; if(mxson[u]) dfs2(mxson[u],tp,CurDist+distofa[mxson[u]]); for(int i=head[u];i;i=nx[i]) { int v=to[i]; if(v==fa[u] || v==mxson[u]) continue; dfs2(v,v,CurDist+distofa[v]); }}int Query_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;}ll tmp,k[MAXN*50],b[MAXN*50];ll calc(int seg,int x){ return k[seg]*dist[x]+b[seg];}int n,m,cnt=0;ll ans;struct SegTree{ int nodecnt; SegTree(){nodecnt=0;} struct node { int ls,rs,id; ll mi; node(){ls=rs=id=0;mi=inf;} }Tree[MAXN<<2];#define root Tree[o]#define lson Tree[root.ls]#define rson Tree[root.rs] void BuildTree(int l,int r) { int o=++nodecnt; if(l==r) return; int mid=(l+r)>>1; root.ls=nodecnt+1; BuildTree(l,mid); root.rs=nodecnt+1; BuildTree(mid+1,r); } void pushup(int o,int l,int r) { if(root.id) root.mi=k[root.id]<0?calc(root.id,r):calc(root.id,l); else root.mi=inf; if(l<r) { root.mi=min(root.mi,lson.mi); root.mi=min(root.mi,rson.mi); } } void upd(int o,int l,int r,int L,int R,int seg) { if(L<=l && r<=R) { if(!root.id) { root.id=seg; pushup(o,l,r); return; } bool f1=calc(root.id,l)<calc(seg,l); bool f2=calc(root.id,r)<calc(seg,r); if(f1==f2 || l==r) { if(!f1) { root.id=seg; pushup(o,l,r); } return; } int mid=(l+r)>>1; bool f3=calc(root.id,mid)<calc(seg,mid); if(f1==f3) { if(f1) upd(root.rs,mid+1,r,L,R,seg); else upd(root.rs,mid+1,r,L,R,root.id),root.id=seg; } else { if(f1) upd(root.ls,l,mid,L,R,root.id),root.id=seg; else upd(root.ls,l,mid,L,R,seg); } } else { int mid=(l+r)>>1; if(L<=mid) upd(root.ls,l,mid,L,R,seg); if(R>mid) upd(root.rs,mid+1,r,L,R,seg); } pushup(o,l,r); } void query(int o,int l,int r,int L,int R) { if(root.id) { if(k[root.id]<0) ans=min(ans,calc(root.id,min(r,R))); else ans=min(ans,calc(root.id,max(l,L))); } if(L<=l && r<=R) { ans=min(ans,root.mi); return; } if(l==r) return; int mid=(l+r)>>1; if(L<=mid) query(root.ls,l,mid,L,R); if(R>mid) query(root.rs,mid+1,r,L,R); }}T;void Modifiy1(int x,int lca,int A,int B){ tmp=B; while(top[x]!=top[lca]) { k[++cnt]=-A; b[cnt]=tmp+1LL*A*dist[dfn[x]]; int L=dfn[top[x]],R=dfn[x]; T.upd(1,1,n,L,R,cnt); tmp+=1LL*(dist[R]-dist[L]+distofa[top[x]])*A; x=fa[top[x]]; } k[++cnt]=-A; b[cnt]=tmp+1LL*A*dist[dfn[x]]; int L=dfn[lca],R=dfn[x]; T.upd(1,1,n,L,R,cnt); tmp+=1LL*(dist[R]-dist[L])*A;}void Modifiy2(int x,int lca,int A,int B){ tmp+=1LL*(dist[dfn[x]]-dist[dfn[lca]])*A; while(top[x]!=top[lca]) { k[++cnt]=A; b[cnt]=tmp-1LL*A*dist[dfn[x]]; int L=dfn[top[x]],R=dfn[x]; T.upd(1,1,n,L,R,cnt); tmp-=1LL*(dist[R]-dist[L]+distofa[top[x]])*A; x=fa[top[x]]; } if(x!=lca) { k[++cnt]=A; b[cnt]=tmp-1LL*A*dist[dfn[x]]; int L=dfn[lca]+1,R=dfn[x]; T.upd(1,1,n,L,R,cnt); }}void Query(int x,int lca){ while(top[x]!=top[lca]) { int L=dfn[top[x]],R=dfn[x]; T.query(1,1,n,L,R); x=fa[top[x]]; } int L=dfn[lca],R=dfn[x]; T.query(1,1,n,L,R);}int main(){ n=read(),m=read(); for(int i=1;i<n;++i) { int u=read(),v=read(),w=read(); addedge(u,v,w); addedge(v,u,w); } dfs1(1,0); dfs2(1,1,0); T.BuildTree(1,n); while(m--) { int tp=read(); int x=read(),y=read(); int lca=Query_LCA(x,y); if(tp==1) { int A=read(),B=read(); Modifiy1(x,lca,A,B); Modifiy2(y,lca,A,B); } else { ans=inf; Query(x,lca); Query(y,lca); printf("%lld\n",ans); } } return 0;}