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