[bzoj1576] [Usaco2009 Jan]安全路经Travel
看了半天题解。。。。
http://hzwer.com/4019.html http://cxjyxx.me/?p=662
神犇一句“不用多说”蒟蒻弄了半天TAT。。。但实在懒(bu)得(gan)写链剖= =
接题解:
对于当前非树边(u,v),设t=lca(u,v),这条非树边可以去尝试更新t-u和t-v(但不包括t)的最短路长度
将非树边按权值(dis[u]+dis[v]+边的长度)排序后,如果一个点已被更新过就不用去试了(先更新的肯定答案更优)
所以脑补一下就可以发现有时一些连续的点(曾祖父-祖父-父亲-.....)都被更新过,这些点都可以直接跳过。
这时就用到了并查集。。father[i]表示点i所在的 被更新过的点组成的链 ,链最顶端的节点编号。(还没被更新过的话father[i]=0)
接着就相当于联通块的合并,只是这里的“联通块”是树上的已被更新的点组成的链。
并查集部分的复杂度是O(n*alpha(n))的。。。比起链剖来说高明到不知道哪里去了!
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<queue> 5 #include<algorithm> 6 using namespace std; 7 const int maxn=100023; 8 const int maxm=200233; 9 struct edge{ 10 int u,v,val; 11 }E[maxm]; 12 struct ZS{ 13 int pos,dis; 14 }; 15 priority_queue<ZS>q; 16 bool operator <(ZS a,ZS b){ 17 return a.dis>b.dis; 18 } 19 struct zs{ 20 int too,pre; 21 short dis; 22 }e[maxm<<1]; 23 int pre[maxn],last[maxn],dis[maxn],bel[maxn],father[maxn],fa[maxn],dep[maxn]; 24 bool used[maxn],intree[maxm<<1]; 25 int i,j,k,n,m,u,v,tot,TOT,a,b,c,tmpu,tmpv,lastu,lastv; 26 int ra;char rx; 27 28 inline int read(){ 29 rx=getchar();ra=0; 30 while(rx<'0'||rx>'9')rx=getchar(); 31 while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra; 32 } 33 inline void insert(int a,int b,int c){ 34 e[++tot].too=b;e[tot].dis=c;e[tot].pre=last[a];last[a]=tot; 35 e[++tot].too=a;e[tot].dis=c;e[tot].pre=last[b];last[b]=tot; 36 } 37 void spfa(){ 38 int i,j,l,r,now,nowdis; 39 ZS tmp; 40 memset(dis,50,(n+1)<<2); 41 tmp.pos=1;tmp.dis=0;q.push(tmp);dis[1]=0;dep[1]=1; 42 while(!q.empty()){ 43 while(!q.empty()&&used[q.top().pos])q.pop(); 44 if(q.empty())break; 45 now=q.top().pos;used[now]=1; 46 for(i=last[now];i;i=e[i].pre)if(dis[e[i].too]>dis[now]+e[i].dis){ 47 dis[e[i].too]=dis[now]+e[i].dis;pre[e[i].too]=i;fa[e[i].too]=now; 48 dep[e[i].too]=dep[now]+1; 49 tmp.pos=e[i].too,tmp.dis=dis[e[i].too],q.push(tmp); 50 } 51 } 52 } 53 bool cmp(edge a,edge b){ 54 return a.val<b.val; 55 } 56 int getfa(int x){ 57 if(father[x]){father[x]=getfa(father[x]);return father[x];} 58 return x; 59 } 60 int main(){ 61 n=read();m=read(); 62 for(i=1;i<=m;i++)a=read(),b=read(),c=read(),insert(a,b,c); 63 spfa(); 64 for(i=1;i<=n;i++)intree[pre[i]]=1; 65 for(i=1;i<=tot;i+=2)if(!intree[i]&&!intree[i+1]) 66 E[++TOT].u=e[i+1].too,E[TOT].v=e[i].too,E[TOT].val=e[i].dis+dis[e[i].too]+dis[e[i+1].too]; 67 sort(E+1,E+1+TOT,cmp); 68 for(i=1;i<=TOT;i++){ 69 u=E[i].u;v=E[i].v; 70 tmpu=getfa(u);tmpv=getfa(v);lastu=lastv=0; 71 while(tmpu!=tmpv){ 72 if(dep[tmpu]<dep[tmpv])swap(tmpu,tmpv),swap(u,v),swap(lastu,lastv); 73 if(!bel[u]){ 74 bel[u]=i; 75 if(lastu)father[lastu]=u; 76 }else if(lastu)father[lastu]=tmpu; 77 lastu=tmpu;u=fa[lastu];tmpu=getfa(u); 78 }//u表示当前尝试更新的节点,tmpu表示u所在链的最顶端节点,lastu表示上一次更新的节点。 79 } 80 for(i=2;i<=n;i++)if(bel[i])printf("%d\n",E[bel[i]].val-dis[i]);else printf("-1\n"); 81 return 0; 82 }