LuoguP2685 [TJOI2012]桥
题意
题解
原题可以转化成在图上每次删一条边后求最短路
考虑先找到一条最短路
那么每次删掉的边有两种情况:
如果这条边不在最短路上那么答案不变
如果在最短路上
显然这条边会被一个不在最短路上的路径代替,考虑枚举这样一条不在最短路上的边 u -> v
假如这条边在新的最短路上,那么现在的最短路就是 1 -> a - > u - > v - > b - > n
显然要让这条路径尽量小 ,a 点就应该是1 - > n 的最短路 与 1 - > u 的最短路 的分界处,同理 b 也是
那么在 a 与 b 点间被删的边都可能被这条路径代替,原问题就变成了一道区间最值问题
线段树解决
#include<bits/stdc++.h> #define LL long long using namespace std; inline LL read() { LL f = 1 , x = 0; char ch; do { ch = getchar(); if(ch=='-') f=-1; } while(ch<'0'||ch>'9'); do { x=(x<<3) + (x<<1) + ch - '0'; ch = getchar(); }while(ch>='0'&&ch<='9'); return f*x; } const int MAXN = 4e5 + 10; const int MAXM = 4e5 + 10; const long long INF = 1LL << 62; int n,m,s,t; struct node { int to; int ne; long long val; int from; }g[MAXM << 1],G[MAXN << 1],e[MAXN]; int cnt,head[MAXN]; int cnt1,Head[MAXN]; int pre[MAXN]; int path[MAXN],tot; int d[MAXN]; inline void addedge(int u,int v,long long w) { ++cnt;g[cnt].from=u;g[cnt].to=v;g[cnt].ne=head[u];g[cnt].val=w;head[u]=cnt;return; } inline void addedge1(int u,int v) { ++cnt1;pre[v]=u;G[cnt1].from = u;G[cnt1].to = v;d[v]++;G[cnt1].ne = Head[u];Head[u]=cnt1;return; } struct Heap { int u; LL val; friend bool operator < (Heap a1,Heap a2) { return a1.val>a2.val; } }; priority_queue<Heap>pq; long long dis1[MAXN]; long long dis2[MAXN]; inline Heap makenode(int a,long long b) { Heap u; u.u = a; u.val = b; return u; } inline void Dij1() { for(int i=1;i<=n;i++) dis1[i] = INF; dis1[s] = 0; pq.push(makenode(s,0)); while(pq.size()) { long long u = pq.top().u,disu = pq.top().val; pq.pop(); if(disu != dis1[u]) continue; for(int i=head[u];i;i=g[i].ne) { int v = g[i].to; if(dis1[v] > dis1[u] + g[i].val) { dis1[v] = dis1[u] + g[i].val; // pre[v] = u; pq.push(makenode(v,dis1[v])); } } } return; } int dp1[MAXN],id[MAXN],id2[MAXN]; bool vis[MAXN]; inline void DP1() { for(int i=1;i<=m;i++) { if(dis1[e[i].from] + e[i].val == dis1[e[i].to]) addedge1(e[i].from,e[i].to),vis[i]=1; if(dis1[e[i].to] + e[i].val == dis1[e[i].from]) addedge1(e[i].to,e[i].from),vis[i]=1; } for(int i=t;i!=s;i=pre[i]) path[++tot] = i;path[++tot] = s; reverse(path+1,path+tot+1); for(int i=1;i<=tot;i++) id[path[i]] = i,id2[i]=path[i]; for(int i=1;i<=n;i++) dp1[i] = MAXN; for(int i=1;i<=tot;i++) dp1[path[i]] = i; queue<int>q;q.push(s); while(q.size()) { int u = q.front();q.pop(); for(int i=Head[u];i;i=G[i].ne) { int v = G[i].to; if(!id[v]) dp1[v] = min(dp1[v],dp1[u]); d[v]--; if(!d[v]) q.push(v); } } } inline void Dij2() { for(int i=1;i<=n;i++) dis2[i] = INF; dis2[t] = 0; pq.push(makenode(t,0)); while(pq.size()) { long long u = pq.top().u,disu = pq.top().val; pq.pop(); if(disu != dis2[u]) continue; for(int i=head[u];i;i=g[i].ne) { int v = g[i].to; if(dis2[v] > dis2[u] + g[i].val) { dis2[v] = dis2[u] + g[i].val; pq.push(makenode(v,dis2[v])); } } } return; } inline void Clear_Edge() { cnt1 = 0; memset(Head,0,sizeof(Head)); memset(d,0,sizeof(d)); } int dp2[MAXN]; inline void DP2() { Clear_Edge(); for(int i=1;i<=m;i++) { if(dis2[e[i].from] + e[i].val == dis2[e[i].to]) addedge1(e[i].from,e[i].to); if(dis2[e[i].to] + e[i].val == dis2[e[i].from]) addedge1(e[i].to,e[i].from); } for(int i=1;i<=tot;i++) dp2[path[i]] = i; // for(int i=1;i<=n;i++) cout << dp2[i] << " "; // cout << endl; queue<int>q;q.push(t); while(q.size()) { int u = q.front();q.pop(); for(int i=Head[u];i;i=G[i].ne) { int v = G[i].to; if(!id[v]) dp2[v] = max(dp2[v],dp2[u]); d[v]--; if(!d[v]) q.push(v); } } } #define lc o<<1 #define rc o<<1|1 long long tr[MAXN<<2]; inline void build(int o,int l,int r) { if(l == r) { tr[o] = INF; return; } int mid = (l+r)>>1; build(lc,l,mid); build(rc,mid+1,r); tr[o] = INF; } inline int check(int x,int y) { if(!id[x]) return false; if(!id[y]) return false; if(id[y] == id[x] + 1) return id[x]; if(id[x] == id[y] + 1) return id[y]; return false; } inline void update(int o,int l,int r,int x,int y,long long v) { if(x<=l&&r<=y) { tr[o] = min(tr[o],v); return; } // if(l>y||x>r) return; int mid = (l+r)>>1; if(x<=mid) update(lc,l,mid,x,y,v); if(y>mid) update(rc,mid+1,r,x,y,v); // tr[o] = min(tr[lc],tr[rc]); } long long ans[MAXN]; inline void get(int o,int l,int r) { if(l == r) { ans[l] = tr[o]; return; } int mid = (l+r)>>1; tr[lc] = min(tr[lc],tr[o]); get(lc,l,mid); tr[rc] = min(tr[rc],tr[o]);get(rc,mid+1,r); } int main() { n = read(),m = read(); s = 1,t = n; for(int i=1;i<=m;i++) { int u,v,w; e[i].from = u = read(),e[i].to = v = read(),e[i].val = w = read(); addedge(u,v,w); addedge(v,u,w); } Dij1(); DP1(); Dij2(); DP2(); build(1,1,tot-1); // cout << tr[1] << endl; // cout <<tot << endl; // for(int i=1;i<=n;i++) cout << dis1[i] << " " << dis2[i] << endl; for(int i=1;i<=m;i++) { int u = e[i].from , v = e[i].to; //if(check(u,v)) continue; if(vis[i]) continue; // cout << u << " " << v << " "<< dp1[u] <<" " << dp2[v] << " "<<e[i].val+dis1[u]+dis2[v]<<endl; // cout << v << " " << u << " "<< dp1[v] <<" " << dp2[u] << " "<<e[i].val+dis1[v]+dis2[u]<<endl; if(dp1[u]<MAXN&&dp2[v]&&dp1[u]<dp2[v]) update(1,1,tot-1,dp1[u],dp2[v]-1,e[i].val + dis1[u] + dis2[v]); if(dp1[v]<MAXN&&dp2[u]&&dp1[v]<dp2[u]) update(1,1,tot-1,dp1[v],dp2[u]-1,e[i].val + dis1[v] + dis2[u]); // cout << tr[1] << endl; } // cout << dis1[t] << endl; get(1,1,tot-1); long long maxcost = 0; for(int i=1;i<tot;i++) { //cout << ans[i] << " "; maxcost = max(maxcost,ans[i]); } int total = 0; for(int i=1;i<tot;i++) { if(maxcost==ans[i]) total++; } cout << maxcost << " " <<total << endl; return 0; }