bzoj2725 [Violet 6] 故乡的梦 && 4400 tjoi2012 桥 Dijkstra+线段树

题目大意:
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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章