​http://www.elijahqi.win/archives/3291​​​
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

Source

首先我们删除的边一定是在1~n的最短路路径上的一条边 那么假设是x->y并且x是y的父节点 那么我们需要满足 新边A->B 那么可以知道S->A->B->T 只要保证这三部分都不经过x->y即可

那么我们可以知道 A一定不在y的子树内 B一定在y的子树内 因为A所有地方都能走就是不能走到子树里 否则走的就不是最短路了 然后只要B在y的子树内就一定不会经过x->y这条边 因为因为B走到y再走到x再走到y会发现他重复走了 一段路 不如直接走y即可 所以B在y的子树内就可以了

然后找出1~n这条路的这条链 然后给这条链进行标号将深度从浅到深进行标号

然后给其他的点也都标号 标 该点与n节点lca的编号即可 然后考虑枚举每条非树边

每条非树边对应的编号就分别是这条链上的编号 也就是如果我必须经过这条边 那么中间这条链上dep[x]~dep[y]这些边都可以被砍掉 那么我就算一个我必须走这条边的代价 然后去线段树上区间取最小值即可

最后遍历整个线段树 找出最小值的最大即可

#include<queue>
#include<cstdio>
#include<vector>
#include<cctype>
#include<cstring>
#include<algorithm>
#define lc (x<<1)
#define rc (x<<1|1)
#define pa pair<int,int>
using namespace std;
inline char gc(){
static char now[1<<16],*S,*T;
if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
return x*f;
}
const int N=1e5+10;
const int inf=0x3f3f3f3f;
struct node{
int x,y,z,next;
}data[N<<2];
int mn[N<<2],h[N],num=1,path[N],n,m,dis1[N],dis2[N],top,dep[N],fa[N],mx,ans;
bool flag[N],in[N<<2];vector<int>son[N];
inline void dijkstra1(){
priority_queue<pa,vector<pa>,greater<pa> >q;
memset(dis1,0x3f,sizeof(dis1));dis1[1]=0;q.push(make_pair(0,1));
while(!q.empty()){
int x=q.top().second;q.pop();if (flag[x]) continue;flag[x]=1;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y,z=data[i].z;
if(dis1[x]+z<dis1[y]){
fa[y]=x;dis1[y]=dis1[x]+z;in[path[y]]=0;in[path[y]^1]=0;
path[y]=i;in[i]=1;in[i^1]=1;q.push(make_pair(dis1[y],y));
}
}
}
}
inline void dijkstra2(){
priority_queue<pa,vector<pa>,greater<pa> >q;
memset(dis2,0x3f,sizeof(dis2));memset(flag,0,sizeof(flag));
dis2[n]=0;q.push(make_pair(0,n));
while(!q.empty()){
int x=q.top().second;q.pop();if (flag[x]) continue;flag[x]=1;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y,z=data[i].z;
if (dis2[x]+z<dis2[y]){
dis2[y]=dis2[x]+z;q.push(make_pair(dis2[y],y));
}
}
}
}
inline void dfs(int x,int v){
for (int i=0;i<son[x].size();++i){
if (dep[son[x][i]]) continue;
dep[son[x][i]]=v;dfs(son[x][i],v);
}
}
inline void build(int x,int l,int r){
mn[x]=inf;if (l==r) return;int mid=l+r>>1;
build(lc,l,mid);build(rc,mid+1,r);
}
inline void modify(int x,int l,int r,int l1,int r1,int v){
if(l1<=l&&r1>=r) {mn[x]=min(mn[x],v);return;}int mid=l+r>>1;
if (l1<=mid) modify(lc,l,mid,l1,r1,v);if (r1>mid) modify(rc,mid+1,r,l1,r1,v);
}
inline void pushdown(int x){
mn[lc]=min(mn[lc],mn[x]);mn[rc]=min(mn[rc],mn[x]);
}
inline void query(int x,int l,int r){
if (l==r) {mx=max(mx,mn[x]);return;}int mid=l+r>>1;
pushdown(x);query(lc,l,mid);query(rc,mid+1,r);
}
inline void query1(int x,int l,int r){
if (l==r) {if(mx==mn[x]) ++ans;return;}int mid=l+r>>1;
query1(lc,l,mid);query1(rc,mid+1,r);
}int q[N];
int main(){
freopen("bzoj4400.in","r",stdin);
// freopen("bzoj4400.out","w",stdout);
n=read();m=read();
for (int i=1;i<=m;++i){
int x=read(),y=read(),z=read();
data[++num].y=y;data[num].next=h[x];data[num].x=x;h[x]=num;data[num].z=z;
data[++num].y=x;data[num].next=h[y];data[num].x=y;h[y]=num;data[num].z=z;
}dijkstra1();dijkstra2();q[top=1]=n;
for (int i=n;fa[i];i=fa[i]) q[++top]=fa[i];build(1,1,top-1);
for (int i=1,j=top;i<j;++i,--j) swap(q[i],q[j]);
for (int i=1;i<=top;++i) dep[q[i]]=i;
for (int i=1;i<=n;++i) son[fa[i]].push_back(i);
for (int i=1;i<=top;++i) dfs(q[i],dep[q[i]]);
// for (int i=1;i<=n;++i) printf("%d,dep[i]);puts("");
for (int i=2;i<=num;++i){
if (in[i]) continue;
int x=data[i].x,y=data[i].y,xx=dep[x],yy=dep[y];if (xx==yy) continue;
if (xx>yy) swap(x,y),swap(xx,yy);int dis=dis1[x]+dis2[y]+data[i].z;
//printf("%d %d\n",xx,yy);
modify(1,1,top-1,xx,yy-1,dis);//printf("%d\n",dis);
}mx=0;query(1,1,top-1);query1(1,1,top-1);
if(mx==dis1[n]) ans=m;
printf("%d %d\n",mx,ans);
return 0;
}