题目大意:
2725: 有n个点,m条边的图,有边权,给定S(起始点)和T(终点),然后有q个询问,问原删除某一条边后的S到T的最短路。
4400:有n个点,m条边的图,有边权,问删除哪些边能使从1号节点到n的最短路径最长。
题目分析:
2725:
我们先随便找出一条最短路,如果删除的边不在最短路上,很显然走最短路是最近的,直接输出最短路长度即可。
当询问的边是最短路上的边的时候:
如果我们强制不走最短路上的某条边的话,那就必须要走非最短路上的某条边。
那我们假设这条必须要走的非最短路上的某条边为x->y。
于是我们走的路径一定是形如S->a->x->y->b->T。
我们定义a和b是最短路径上的两个位置,a代表从S走到x的最短路最早在什么位置离开最短路径,b代表从y走到T的最短路最晚在什么位置回到最短路径继续走。
如果你看上面的解释仍然一脸萌比的话,看这个图直观的理解一下:
(蓝色边为最短路径,红色边代表必须要走的非最短路上的边)
对于每一个点来说,a和b的位置是固定的。
那我们来考虑如何求这个a和b。
拿a来举例。
如果我们把S作为源点做一棵最短路径树的话,那么a相当于x和T的LCA(当然我们不需要真的把树建出来QAQ)。
先跑出S到所有点的最短路,然后把最短路上的点从S到T依次拎出来,把第i个点能以最短路到达(且不经过最短路径上的其他点)的所有点都标记为i,注意之前标记过的就不要在标记了。
b同理。
令fs[i]代表S到i的最短路,ft[i]代表i到T的最短路。
这样我们枚举每一条不在最短路径上的边x->y,那么当删去a~b中间的最短路径上的边时,fs[x]+(x->y)+ft[y]就可以作为一个答案。
这样我们把最短路径拎出来建一棵线段树,然后在枚举每一条边,更新a~b的值。
然后就可以求出每一条最短路上的边的答案。
4400:
和上一道题思路是一样的,最后统计答案的时候取个最大值记录一下数量就行了。
!!! 跑最短路的时候不要用spfaQAQ!!!
(我是不会告诉你们我用Dijkstra 1s能跑过的点,spfa跑了100s的QAQ,可能是我太菜了,不加优化的spfa果然是无法与Dijkstra抗衡的么泪目>_<)
(给泥萌看看我写的像shi一样的代码=。=)
bzoj2725代码:
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#define ls(c) (c<<1)
#define rs(c) (c<<1|1)
#define N 220000
using namespace std;
typedef long long LL;
const LL INF=0x3f3f3f3f3f3f3f3fll;
inline LL Min(LL x,LL y) { return x<y?x:y; }
inline int Abs(int x) { return x<0?-x:x; }
int n,m,S,T,Q,maxn;
int fir[N],nes[N<<1],v[N<<1],q[N<<1],tot=1;
LL seg[N<<2],ans[N],fs[N],ft[N];
int lx[N],rx[N],id[N],xl[N];
bool mark[N],vis[N];
struct point{
LL val;
int pos;
point(LL val,int pos):val(val),pos(pos){}
bool operator < (const point &c) const { return val>c.val; }
};
priority_queue<point> dl;
void edge(int x,int y,int z)
{
v[++tot]=y;
q[tot]=z;
nes[tot]=fir[x];
fir[x]=tot;
}
#define edge(x,y,z) edge(x,y,z),edge(y,x,z)
void update(int c,int l,int r,int x,int y,LL v)
{
if(x<=l && y>=r) { seg[c]=Min(seg[c],v); return; }
int mid=l+r>>1;
if(x<=mid) update(ls(c),l,mid,x,y,v);
if(y>mid) update(rs(c),mid+1,r,x,y,v);
}
void push_down(int c,int l,int r)
{
if(l==r) { ans[l]=seg[c]; return; }
int mid=l+r>>1;
seg[ls(c)]=Min(seg[ls(c)],seg[c]); push_down(ls(c),l,mid);
seg[rs(c)]=Min(seg[rs(c)],seg[c]); push_down(rs(c),mid+1,r);
}
void Dijkstra(int S,LL *f)
{
static int c;
memset(vis,false,sizeof(vis));
for(int i=0;i<=n;i++) f[i]=INF;
f[S]=0; c=S;
for(int i=1;i<=n;i++) dl.push(point(INF,i));
for(int i=1;i<n;i++)
{
vis[c]=true;
for(int t=fir[c];t;t=nes[t])
if(!vis[v[t]]) dl.push(point(f[c]+q[t],v[t]));
while(vis[dl.top().pos]) dl.pop();
c=dl.top().pos;
f[c]=dl.top().val;
dl.pop();
}
}
void bfs(int i,LL *f,int *x)
{
queue<int> dl;
static int c;
dl.push(xl[i]); x[xl[i]]=i;
while(!dl.empty())
{
c=dl.front();
dl.pop();
for(int t=fir[c];t;t=nes[t])
if(f[v[t]]==f[c]+q[t] && !id[v[t]] && !x[v[t]])
{
x[v[t]]=i;
dl.push(v[t]);
}
}
}
int main()
{
int x,y,z;
memset(seg,0x3f,sizeof(seg));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
edge(x,y,z);
}
scanf("%d%d",&S,&T);
if(S==T) { for(scanf("%d",&Q);Q;Q--) puts("0"); return 0; }
Dijkstra(S,fs);
if(fs[T]==INF) { for(scanf("%d",&Q);Q;Q--) puts("Infinity"); return 0; }
Dijkstra(T,ft);
for(int c=S;c!=T;)
{
mark[c]=true;
xl[++maxn]=c;
id[c]=maxn;
for(int t=fir[c];t;t=nes[t])
if(q[t]+ft[v[t]]==ft[c]) { c=v[t]; break; }
}
xl[maxn+1]=T; id[T]=maxn+1;
for(int i=1;i<=maxn;i++) bfs(i,fs,lx);
for(int i=maxn+1;i>=1;i--) bfs(i,ft,rx);
for(int i=1;i<=n;i++)
for(int t=fir[i];t;t=nes[t])
{
if(id[i] && id[v[t]] && Abs(id[i]-id[v[t]])==1) continue;
if(lx[i]<rx[v[t]] && lx[i] && rx[v[t]]) update(1,1,maxn,lx[i],rx[v[t]]-1,fs[i]+q[t]+ft[v[t]]);
}
push_down(1,1,maxn);
scanf("%d",&Q);
while(Q--)
{
scanf("%d%d",&x,&y);
if(id[x]>id[y]) swap(x,y);
if(id[x] && id[y] && id[y]-id[x]==1)
{
if(ans[id[x]]==INF) puts("Infinity");
else printf("%lld\n",ans[id[x]]);
}
else printf("%lld\n",fs[T]);
}
fclose(stdin);
fclose(stdout);
return 0;
}
bzoj4400代码:
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#define ls(c) (c<<1)
#define rs(c) (c<<1|1)
#define N 220000
using namespace std;
typedef long long LL;
const LL INF=0x3f3f3f3f3f3f3f3fll;
inline LL Min(LL x,LL y) { return x<y?x:y; }
inline int Abs(int x) { return x<0?-x:x; }
int n,m,S,T,Q,maxn;
int fir[N],nes[N<<1],v[N<<1],q[N<<1],tot=1;
LL seg[N<<2],ans[N],fs[N],ft[N];
int lx[N],rx[N],id[N],xl[N];
bool mark[N<<1],vis[N];
struct point{
LL val;
int pos;
point(LL val,int pos):val(val),pos(pos){}
bool operator < (const point &c) const { return val>c.val; }
};
priority_queue<point> dl;
void edge(int x,int y,int z)
{
v[++tot]=y;
q[tot]=z;
nes[tot]=fir[x];
fir[x]=tot;
}
#define edge(x,y,z) edge(x,y,z),edge(y,x,z)
void update(int c,int l,int r,int x,int y,LL v)
{
if(x<=l && y>=r) { seg[c]=Min(seg[c],v); return; }
int mid=l+r>>1;
if(x<=mid) update(ls(c),l,mid,x,y,v);
if(y>mid) update(rs(c),mid+1,r,x,y,v);
}
void push_down(int c,int l,int r)
{
if(l==r) { ans[l]=seg[c]; return; }
int mid=l+r>>1;
seg[ls(c)]=Min(seg[ls(c)],seg[c]); push_down(ls(c),l,mid);
seg[rs(c)]=Min(seg[rs(c)],seg[c]); push_down(rs(c),mid+1,r);
}
void Dijkstra(int S,LL *f)
{
static int c;
memset(vis,false,sizeof(vis));
for(int i=0;i<=n;i++) f[i]=INF;
f[S]=0; c=S;
for(int i=1;i<=n;i++) dl.push(point(INF,i));
for(int i=1;i<n;i++)
{
vis[c]=true;
for(int t=fir[c];t;t=nes[t])
if(!vis[v[t]]) dl.push(point(f[c]+q[t],v[t]));
while(vis[dl.top().pos]) dl.pop();
c=dl.top().pos;
f[c]=dl.top().val;
dl.pop();
}
}
void bfs(int i,LL *f,int *x)
{
queue<int> dl;
static int c;
dl.push(xl[i]); x[xl[i]]=i;
while(!dl.empty())
{
c=dl.front();
dl.pop();
for(int t=fir[c];t;t=nes[t])
if(f[v[t]]==f[c]+q[t] && !id[v[t]] && !x[v[t]])
{
x[v[t]]=i;
dl.push(v[t]);
}
}
}
int main()
{
int x,y,z;
memset(seg,0x3f,sizeof(seg));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
edge(x,y,z);
}
S=1; T=n;
Dijkstra(S,fs);
Dijkstra(T,ft);
for(int c=S;c!=T;)
{
mark[c]=true;
xl[++maxn]=c;
id[c]=maxn;
for(int t=fir[c];t;t=nes[t])
if(q[t]+ft[v[t]]==ft[c]) { c=v[t]; mark[t]=true; break; }
}
xl[maxn+1]=T; id[T]=maxn+1;
for(int i=1;i<=maxn;i++) bfs(i,fs,lx);
for(int i=maxn+1;i>=1;i--) bfs(i,ft,rx);
for(int i=1;i<=n;i++)
for(int t=fir[i];t;t=nes[t])
{
if(mark[t]) continue;
if(lx[i]<rx[v[t]] && lx[i] && rx[v[t]]) update(1,1,maxn,lx[i],rx[v[t]]-1,fs[i]+q[t]+ft[v[t]]);
}
push_down(1,1,maxn);
int cnt=0;
LL d=0;
for(int i=1;i<=maxn;i++)
{
if(ans[i]>d) d=ans[i],cnt=1;
else if(ans[i]==d) cnt++;
}
if(d==fs[T]) cnt+=m-maxn;
printf("%lld %d\n",d,cnt);
return 0;
}