BZOJ 1576 树剖+LCT
题意:给定一张图,保证 $1$ 号点到其他所有点的最短路径是唯一的,求:对于点 $i$,不经过 $1$ 到 $i$ 最短路径上最后一条边的最短路.
题解:可以先建出最短路树,然后枚举每一条非树边.
对于一条非树边,影响的只是 $(u,lca)$,$(lca,v)$ 这些点的答案,然后你发现可以写成 $dep[a]-dep[u]+val[i]+dep[v]$
对于 $a$ 来说,第一项是固定的,后面的几项对于一个链来说都是相同的,所以直接用 $LCT$ 维护区间最小值就行了.
#include <bits/stdc++.h> #define N 100003 #define M 200005 #define ll long long #define inf 1000000000000 #define inf2 10000000000 #define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout) using namespace std; ll output[N]; vector<int>G[N]; int lst[N],from[N],n,m; namespace Dij { ll val[M<<1],d[N]; int hd[N],to[M<<1],nex[M<<1],done[N],edges,s; struct Node { int u; ll dis; Node(int u=0,ll dis=0):u(u),dis(dis){} bool operator<(Node b) const { return b.dis<dis; } }; priority_queue<Node>q; void addedge(int u,int v,ll c) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c; } void dijkstra() { memset(d,0x3f,sizeof(d)); d[s]=0ll; q.push(Node(s,0ll)); while(!q.empty()) { Node e=q.top(); q.pop(); int u=e.u; if(done[u]) continue; done[u]=1; for(int i=hd[u];i;i=nex[i]) { int v=to[i]; if(d[u]+val[i]<d[v]) { lst[v]=i; from[v]=u; d[v]=d[u]+val[i]; q.push(Node(v, d[v])); } } } for(int i=2;i<=n;++i) G[from[i]].push_back(i); } } namespace tree { int tim; int size[N],dfn[N],top[N],dep[N],son[N],fa[N]; void dfs1(int u,int ff) { fa[u]=ff,size[u]=1,dep[u]=dep[ff]+1; for(int i=0;i<G[u].size();++i) { dfs1(G[u][i],u); size[u]+=size[G[u][i]]; if(size[G[u][i]]>size[son[u]]) son[u]=G[u][i]; } } void dfs2(int u,int tp) { top[u]=tp; if(son[u]) dfs2(son[u], tp); for(int i=0;i<G[u].size();++i) if(G[u][i]!=son[u]) dfs2(G[u][i], G[u][i]); } int LCA(int x,int y) { while(top[x]!=top[y]) { dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]]; } return dep[x]<dep[y]?x:y; } }; struct Link_Cut_Tree { #define lson p[x].ch[0] #define rson p[x].ch[1] int sta[N]; struct Node { int ch[2],tag,f,rev; ll minn,pu,val; }p[N]; inline int get(int x) { return p[p[x].f].ch[1]==x; } inline int isrt(int x) { return !(p[p[x].f].ch[0]==x||p[p[x].f].ch[1]==x); } inline void pushup(int x) { p[x].minn=p[x].val; if(lson) p[x].minn=min(p[x].minn, p[lson].minn); if(rson) p[x].minn=min(p[x].minn, p[rson].minn); } void markrev(int x) { if(x) swap(lson,rson), p[x].rev^=1; } void marktag(int x,ll v) { if(x) { p[x].val=min(p[x].val,v); if(!p[x].tag || p[x].pu>v) p[x].pu=v, p[x].tag=1; pushup(x); } } void pushdown(int x) { if(!x) return; if(p[x].tag) { if(lson) marktag(lson, p[x].pu); if(rson) marktag(rson, p[x].pu); p[x].tag=0; } if(p[x].rev) { if(lson) markrev(lson); if(rson) markrev(rson); p[x].rev=0; } } inline void rotate(int x) { int old=p[x].f, fold=p[old].f, which=get(x); if(!isrt(old)) p[fold].ch[p[fold].ch[1]==old]=x; p[old].ch[which]=p[x].ch[which^1], p[p[old].ch[which]].f=old; p[x].ch[which^1]=old, p[old].f=x, p[x].f=fold; pushup(old), pushup(x); } inline void splay(int x) { int u=x,v=0,fa; for(sta[++v]=u; !isrt(u); u=p[u].f) sta[++v]=p[u].f; for(;v;--v) pushdown(sta[v]); for(u=p[u].f;(fa=p[x].f)!=u;rotate(x)) if(p[fa].f!=u) rotate(get(fa)==get(x)?fa:x); } void Access(int x) { for(int y=0;x;y=x,x=p[x].f) splay(x), rson=y, pushup(x); } void makeroot(int x) { Access(x), splay(x), markrev(x); } void split(int x,int y) { makeroot(x), Access(y), splay(y); } int find(int x) { for(pushdown(x); rson ; pushdown(x)) { x=rson; } return x; } #undef lson #undef rson }lct; void build_tree(int u,int ff) { lct.p[u].f=ff; lct.p[u].val=inf; lct.pushup(u); for(int i=0;i<G[u].size();++i) build_tree(G[u][i], u); } int main() { // setIO("input"); int i,j; scanf("%d%d",&n,&m); for(i=1;i<=m;++i) { int u,v,c; scanf("%d%d%d",&u,&v,&c); Dij::addedge(u,v,1ll*c); Dij::addedge(v,u,1ll*c); } Dij::s=1; Dij::dijkstra(); tree::dfs1(1,0); tree::dfs2(1,1); build_tree(1,0); for(i=1;i<=n;++i) { for(j=Dij::hd[i];j;j=Dij::nex[j]) { int v=Dij::to[j]; if(lst[v]==j) continue; int lca=tree::LCA(i,v); lct.split(v,lca); int pp=lct.find(lct.p[lca].ch[0]); if(pp) { lct.split(v, pp); lct.marktag(pp, Dij::d[v]+Dij::d[i]+Dij::val[j]); } } } for(i=2;i<=n;++i) { lct.Access(i); lct.splay(i); if(lct.p[i].val>=inf2) printf("-1\n"); else printf("%lld\n",lct.p[i].val-Dij::d[i]); } return 0; }