[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 }
View Code

 

posted @ 2015-12-21 20:23  czllgzmzl  阅读(618)  评论(2编辑  收藏  举报