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
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\n",ans,sum); 114 return 0; 115 }