USACO09JAN 安全出行Safe Travel
题解:
因为这个东西占的是最短路的最后一条边,我们可以建出最短路树。
一遍dij即可。
如果这个图就是一棵树,那么所有答案全为-1;
所以说非树边更新了答案。
现在让我们开一棵 2,2,4-三甲基-3-乙基戊烷 ,就是#r巨佬的231树。
如果6- - ->7,那3和7的答案都可以由1->2->6- - ->7->3->1更新。
如果7- - ->8,那么只有8的答案可被1->3->7- - ->8->3->1更新。
说白了,如果f- - ->t而且t不是f的祖先,那t到lca(f,t)路径上除了lca的所有点都能被更新。
树链修改,树剖+线段树。
最后dp[i]=min(DP[i])-dis[i];
都表示啥就不说了。
代码:
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 100050 #define M 200050 #define ll long long inline int rd() { int f=1,c=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();} return f*c; } int n,m,hed[N],cnt=-1; struct EG { int f,t,v,nxt; bool use; }e[2*M]; void ae(int f,int t,int v) { e[++cnt].f = f; e[cnt].t = t; e[cnt].v = v; e[cnt].nxt = hed[f]; hed[f] = cnt; } struct node { int x; ll d; node(){} node(int x,ll d):x(x),d(d){} friend bool operator < (node a,node b) { return a.d>b.d; } }; ll dis[N]; bool vis[N]; void dij() { priority_queue<node>q; q.push(node(1,0)); memset(dis,0x3f,sizeof(dis)); dis[1]=0; while(!q.empty()) { node tp = q.top(); q.pop(); int u = tp.x; if(vis[u])continue; vis[u]=1; for(int j=hed[u];~j;j=e[j].nxt) { int to = e[j].t; if(dis[to]>dis[u]+e[j].v) { dis[to]=dis[u]+e[j].v; q.push(node(to,dis[to])); } } } } bool in_tree[N]; int fa[N]; void build() { queue<int>q; q.push(1); in_tree[1]=1; while(!q.empty()) { int u = q.front(); q.pop(); for(int j=hed[u];~j;j=e[j].nxt) { int to = e[j].t; if(in_tree[to]||dis[to]!=dis[u]+e[j].v)continue; in_tree[to]=1; e[j].use=1;e[j^1].use=1; q.push(to); } } } int siz[N],top[N],son[N],dep[N]; void dfs1(int u,int f) { fa[u]=f; dep[u]=dep[f]+1; siz[u]=1; for(int j=hed[u];~j;j=e[j].nxt) { int to = e[j].t; if(!e[j].use||to==f)continue; dep[to]=dep[u]+1; dfs1(to,u); siz[u]+=siz[to]; if(siz[to]>siz[son[u]])son[u]=to; } } int tin[N],tim,pla[N]; void dfs2(int u,int tp) { top[u]=tp;tin[u]=++tim;pla[tim]=u; if(son[u]) { dfs2(son[u],tp); for(int j=hed[u];~j;j=e[j].nxt) { int to = e[j].t; if(!e[j].use||to==son[u]||to==fa[u])continue; dfs2(to,to); } } } int get_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; } const ll inf = 0x3f3f3f3f3f3f3f3fll; ll dp[N]; struct segtree { ll v[N<<2],tag[N<<2]; void renew(int u,ll d) { if(d<v[u]) { v[u]=d; tag[u]=d; } } void pushdown(int u) { if(tag[u]!=inf) { renew(u<<1,tag[u]); renew(u<<1|1,tag[u]); tag[u]=inf; } } void build(int l,int r,int u) { v[u]=tag[u]=inf; if(l==r)return ; int mid = (l+r)>>1; build(l,mid,u<<1); build(mid+1,r,u<<1|1); } void insert(int l,int r,int u,int ql,int qr,ll d) { if(l==ql&&r==qr) { renew(u,d); return ; } pushdown(u); int mid = (l+r)>>1; if(qr<=mid)insert(l,mid,u<<1,ql,qr,d); else if(ql>mid)insert(mid+1,r,u<<1|1,ql,qr,d); else insert(l,mid,u<<1,ql,mid,d),insert(mid+1,r,u<<1|1,mid+1,qr,d); } void print(int l,int r,int u) { if(l==r) { dp[pla[l]] = v[u]-dis[pla[l]]; return ; } pushdown(u); int mid = (l+r)>>1; print(l,mid,u<<1); print(mid+1,r,u<<1|1); } }tr; int main() { n=rd(),m=rd(); memset(hed,-1,sizeof(hed)); for(int f,t,v,i=1;i<=m;i++) { f=rd(),t=rd(),v=rd(); ae(f,t,v),ae(t,f,v); } dij(); build(); dfs1(1,0); dfs2(1,1); tr.build(1,n,1); for(int f,t,j=0;j<=cnt;j++) { if(e[j].use)continue; f = e[j].f,t = e[j].t; int lca = get_lca(f,t); if(lca==t)continue; ll tmp = dis[f]+dis[t]+e[j].v; int now=top[t]; while(dep[now]>dep[lca]) { tr.insert(1,n,1,tin[now],tin[t],tmp); t = fa[now],now = top[t]; } if(dep[t]>dep[lca]) tr.insert(1,n,1,tin[lca]+1,tin[t],tmp); } tr.print(1,n,1); for(int i=2;i<=n;i++) { if(dp[i]>10000000000ll)dp[i]=-1; printf("%lld\n",dp[i]); } return 0; }