bzoj4400: tjoi2012 桥

Description

有n个岛屿,m座桥,每座桥连通两座岛屿,桥上会有一些敌人,玩家只有消灭了桥上的敌人才能通过,与此同时桥上的敌人会对玩家造成一定伤害。而且会有一个大Boss镇守一座桥,以玩家目前的能力,是不可能通过的。而Boss是邪恶的,Boss会镇守某一座使得玩家受到最多的伤害才能从岛屿1到达岛屿n(当然玩家会选择伤害最小的路径)。问,Boss可能镇守岛屿有哪些。

Input

第一行两个整数n,m
接下来m行,每行三个整数s,t,c,表示一座连接岛屿s和t的桥上的敌人会对玩家造成c的伤害。

Output

一行,两个整数d,cnt,d表示有Boss的情况下,玩家要受到的伤害,cnt表示Boss有可能镇守的桥的数目。

Sample Input

3 4
1 2 1
1 2 2
2 3 1
2 3 1

Sample Output

3 1

HINT

100%的数据,1<=n<=100000,1<=m<=200000,1<=c<=10000,数据保证玩家可以从岛屿1到达岛屿n

 
题解:
先从s(即1号点)进行一次dijkstra+heap,求出每个点u记录一下fa,fa满足dis[fa]+val=dis[u]
这样的父子关系可以形成一棵树,叫做最短路径树(并不用建出来)
显然删去s到t那一条路径上的边才有可能影响结果

我们注意到删边的时候,

新的最短路分成三部分

1、最短路树上某条路径S-A

 

2、跨越路径A-B

3、最后走最短路径B-T

 

只要保证三部分都不经过要删的X-Y边就可以了

这里设定X是Y的父亲

 

第一部分:整棵树除去Y为根的子树,剩下的都能走

 

这也就限定了A不在Y的子树中

第三部分:B-T要不经过X-Y,可以发现,只要B在Y的子树中就一定不会经过X-Y这条边

 

反证:假设经过了X-Y,那么路径一定是B-X-Y

 

 

而B-X最短路就是X-B最短路,按最短路树走要经过Y

于是这条路径变成了B-Y-X-Y-T,不如B-Y-T

 

我们定义一个节点P的等级为它在S-T路径上的最近祖先在最短路径树上的深度,也就是dep[LCA(T,P)]

接下来考虑第二部分,由于A不在Y的子树中,B在Y的子树中,可以看出这一部分一定是越过树的等级的一条路径

 

接下来我们首先证明第二部分的路径只有一条边

注意到路径跨越了X-Y这条边,所以路径上一定有边(U,V),使得LV(U)<=X,LV(V)>=Y

 

这样我们直接抓出来S到U的最短路径和V到T的最短路径,然后配合这条边,得出的新路径合法而且不比现在的长

于是第二部分只有一条边

 

于是,如果预处理出来S到任一点最短路,T到任意点最短路,那么只要知道了第二部分这条边,整条路径长度就知道了
于是我们考虑枚举每条非树边,注意到这样一条边可以更新很多的X-Y,用线段树维护一下即可
code:
  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<algorithm>
  6 #define maxn 100005
  7 #define maxm 400005
  8 #define inf 1061109567
  9 using namespace std;
 10 char ch;
 11 bool ok;
 12 void read(int &x){
 13     for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
 14     for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
 15     if (ok) x=-x;
 16 }
 17 int n,m,u[maxm],v[maxm],c[maxm];
 18 int tot=1,now[maxn],son[maxm],pre[maxm],val[maxm];
 19 void put(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
 20 int siz,pos[maxn],dis[maxn][2],path[maxn];
 21 bool bo[maxn],flag[maxm];
 22 struct Heap{
 23     int num,val;
 24 }heap[maxn];
 25 void heap_swap(Heap &a,Heap &b){swap(pos[a.num],pos[b.num]),swap(a,b);}
 26 void up(int son){
 27     int fa=son>>1;
 28     while (fa){
 29         if (heap[fa].val<=heap[son].val) break;
 30         heap_swap(heap[fa],heap[son]);
 31         son=fa,fa>>=1;
 32     }
 33 }
 34 void down(){
 35     int fa=1,son=fa<<1;
 36     while (son<=siz){
 37         if (son+1<=siz&&heap[son+1].val<heap[son].val) son++;
 38         if (heap[fa].val<=heap[son].val) break;
 39         heap_swap(heap[fa],heap[son]);
 40         fa=son,son<<=1;
 41     }
 42 }
 43 void dijkstra(int s,int op){
 44     memset(bo,0,sizeof(bo));
 45     memset(pos,0,sizeof(pos));
 46     siz=0;
 47     heap[++siz]=(Heap){s,0},pos[s]=siz;
 48     for (;siz;){
 49         int u=heap[1].num,d=heap[1].val;
 50         bo[u]=1,dis[u][op]=d,heap_swap(heap[1],heap[siz--]),down();
 51         for (int p=now[u],v=son[p];p;p=pre[p],v=son[p])
 52             if (!bo[v]){
 53                 if (!pos[v]){
 54                     heap[++siz]=(Heap){v,d+val[p]},pos[v]=siz,up(pos[v]);
 55                     if (!op) path[v]=p;
 56                 }
 57                 else if (heap[pos[v]].val>d+val[p]){
 58                     heap[pos[v]].val=d+val[p],up(pos[v]);
 59                     if (!op) path[v]=p;
 60                 }
 61             }
 62     }
 63 }
 64 int cnt,tmp[maxn],list[maxn],dep[maxn];
 65 void prepare(){
 66     for (int u=n;u;u=son[path[u]^1]) tmp[++cnt]=u;
 67     for (int i=1;i<=cnt;i++) list[cnt-i+1]=tmp[i];
 68     for (int i=1;i<=cnt;i++) dep[list[i]]=i;
 69     for (int i=1;i<=n;i++) if (!dep[i]){
 70         int u=i,d=0;
 71         while (!dep[u]) u=son[path[u]^1];
 72         d=dep[u],u=i;
 73         while (!dep[u]) dep[u]=d,u=son[path[u]^1];
 74     }
 75     for (int u=1;u<=n;u++) if (path[u]) flag[path[u]>>1]=1;
 76 }
 77 int dam[maxn];
 78 struct seg{
 79     #define ls k<<1
 80     #define rs (k<<1)+1
 81     int cov[maxn<<3];
 82     void init(){memset(cov,63,sizeof(cov));}
 83     void modify(int k,int l,int r,int x,int y,int v){
 84         if (l==x&&r==y){cov[k]=min(cov[k],v);return;}
 85         int m=(l+r)>>1;
 86         if (y<=m) modify(ls,l,m,x,y,v);
 87         else if (x<=m) modify(ls,l,m,x,m,v),modify(rs,m+1,r,m+1,y,v);
 88         else modify(rs,m+1,r,x,y,v);
 89     }
 90     void query(int k,int l,int r,int ans){
 91         ans=min(ans,cov[k]);
 92         if (l==r){dam[l]=ans;return;}
 93         int m=(l+r)>>1;
 94         query(ls,l,m,ans),query(rs,m+1,r,ans);
 95     }
 96 }T;
 97 void work(int u,int v,int c){
 98     if (dep[u]==dep[v]) return;
 99     if (dep[u]>dep[v]) swap(u,v);
100     T.modify(1,1,cnt-1,dep[u],dep[v]-1,dis[u][0]+c+dis[v][1]);
101 }
102 int main(){
103     read(n),read(m);
104     for (int i=1;i<=m;i++) read(u[i]),read(v[i]),read(c[i]),put(u[i],v[i],c[i]),put(v[i],u[i],c[i]);
105     dijkstra(1,0),dijkstra(n,1);
106     prepare(),T.init();
107     for (int i=1;i<=m;i++) if (!flag[i]) work(u[i],v[i],c[i]);
108     T.query(1,1,cnt-1,inf);
109     int ans=0,sum=0;
110     for (int i=1;i<cnt;i++) ans=max(ans,dam[i]);
111     for (int i=1;i<cnt;i++) if (ans==dam[i]) sum++;
112     if (ans==dis[n][0]) sum=m;
113     printf("%d %d
",ans,sum);
114     return 0;
115 }
原文地址:https://www.cnblogs.com/chenyushuo/p/5121234.html