BZOJ 2725 [Violet 6]故乡的梦

本文介绍了一种结合堆优化Dijkstra算法与线段树的数据结构来解决特定类型的最短路径问题的方法。通过分析无向图中删除某条边后的最短路径变化,并利用堆优化Dijkstra算法进行高效计算,最后借助线段树更新和查询路径,以应对动态变化的图结构。

堆优dijkstra+线段树

膜:http://blog.csdn.net/popoqqq/article/details/47841783

为了表达清楚,记不删边时最短路为E1,删去某一条E1上的边之后的最短路为E2

显然E2一定是形如:S->沿着E1走到某一个在E1上点的S’->沿着不属于E1的一些边走到某一在E1上点的T’->沿着E1走到T

而且可以证明,上面提到的E2中不属于E1的那些边(组成一条路径)中,一定存在至少一条边,记它的两端点为u,v,使得E2上沿着S->u的路径是S->u在原图中的最短路,E2上沿着v->T的路径是v->T在原图中的最短路。

这个可以通过反证法证明,前提是原图为无向图。

然而其实这一题我并没有AC。。。不知道是因为复杂度退化了还是常数太大了,一直T。。。

#include<map>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
#define cmin(u,v) (u)>(v)?(u)=(v):0
#define mkp(a,b) (1ll*a*N+b)
#define reg register
using namespace std;
int in()
{
    register long long r = 0;
    register char c = getchar();
    while(c<'0'||c>'9')c = getchar();
    while(c>='0'&&c<='9')r = r*10+c-'0', c=getchar();
    return r;
}
char ss[100];
inline void out(long long x)
{
    if(x==0) {putchar(48); return;}
    char *s=ss;
    while(x) *(++s)=x%10, x/=10;
    while(s!=ss) putchar((*(s--))+48);
    putchar('\n');
}
map<long long,bool> PathEdge;
map<long long,int> PathId;
struct node
{
    int id;
    long long dis;
    node(){}
    node(int a, long long b):id(a),dis(b){}
}heap[N<<1];
struct Segment_tree
{
    int l, r;
    long long val, lazy;
}t[N*5];
struct edge{int from,next,to, val;}e[N<<1];
const long long INF = 1ll<<61;
long long dis[N], ds[N], dt[N], print[N];
int n, last[N], ecnt=1, fa[N], fs[N], ft[N], ll[N], rl[N], mapp[N], tcnt, ct[N], ctt, tot;
bool vis[N], PathPoint[N];
void addedge(int a, int b, int c)
{
    e[++ecnt]=(edge){a,last[a],b,c};
    last[a]=ecnt;
    PathId[mkp(a,b)]=ecnt;
}
void heap_add(node x)
{
    heap[++tot]=x;
    for(reg int i=tot,j=i>>1;j;i=j,j>>=1)
    {
        if(heap[j].dis>heap[i].dis)
            swap(heap[j],heap[i]);
        else break;
    }
}
void heap_pop()
{
    heap[1]=heap[tot--];
    for(reg int i=1,j=i<<1;j<=tot;i=j,j<<=1)
    {
        if(j<tot&&heap[j].dis>heap[j|1].dis)j|=1;
        if(heap[j].dis<heap[i].dis)
            swap(heap[j],heap[i]);
        else break; 
    }
}
void dijk(int s)
{
    memset(vis,0,sizeof(vis));
    memset(dis,0x7f,sizeof(dis));
    heap_add(node(s,dis[s]=0));
    while(tot)
    {
        int x=heap[1].id;
        heap_pop();
        if(vis[x])continue;
        vis[x]=1;
        for(reg int i = last[x]; i; i=e[i].next)
        {
            int y=e[i].to;
            if(vis[y] || dis[x]+e[i].val>=dis[y])continue;
            dis[y]=dis[x]+e[i].val;
            fa[y]=x;
            heap_add(node(y,dis[y]));
        }
    }
}
void dijk2(int s, int *fs, long long *ds)
{
    memset(vis,0,sizeof(vis));
    memset(ds,0x7f,sizeof(dis));
    heap_add(node(s,ds[s]=0));
    while(tot)
    {
        int x=heap[1].id;
        heap_pop();
        if(vis[x])continue;
        vis[x]=1;

        if(PathPoint[fa[x]] && (!PathPoint[x]))
            fs[x]=fa[x];
        else if(PathPoint[x])fs[x]=x;
        else fs[x]=fs[fa[x]];

        for(reg int i = last[x]; i; i=e[i].next)
        {
            int y=e[i].to;
            if(vis[y] || ds[x]+e[i].val>=ds[y])continue;
            ds[y]=ds[x]+e[i].val;
            fa[y]=x;
            heap_add(node(y,ds[y]));
        }
    }   
}
void pushdown(int x)
{
    cmin(t[x<<1].val,t[x].lazy);
    cmin(t[x<<1|1].val,t[x].lazy);
    cmin(t[x<<1].lazy,t[x].lazy);
    cmin(t[x<<1|1].lazy,t[x].lazy);
    t[x].lazy=INF;
}
void merge(int x)
{
    cmin(t[x].val,t[x<<1].val);
    cmin(t[x].val,t[x<<1|1].val);
}
void build(int x, int l, int r)
{
    t[x].l=l; t[x].r=r; t[x].val=INF; t[x].lazy=INF;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
}
void update(int x, int l, int r, long long v)
{
    pushdown(x);
    if(l<=t[x].l && t[x].r<=r)
    {
        cmin(t[x].val,v);
        cmin(t[x].lazy,v);
        return;
    }
    int mid=(t[x].l+t[x].r)>>1;
    if(l<=mid)update(x<<1,l,r,v);
    if(mid+1<=r)update(x<<1|1,l,r,v);
    merge(x);
}
void ask(int x)
{
    pushdown(x);
    if(t[x].l==t[x].r)
    {
        print[t[x].l]=t[x].val;
        return;
    }
    ask(x<<1);
    ask(x<<1|1);
}
int main()
{
    int m, s, t, Q;
    n=in();m=in();
    for(reg int i = 1, a, b, c; i <= m; i++)
    {
        a=in(); b=in(); c=in();
        addedge(a,b,c);
        addedge(b,a,c);
    }

    s=in(); t=in(); Q=in();

    dijk(s);

    PathPoint[s]=1;
    for(reg int pos = t; fa[pos]; pos=fa[pos])
    {
        ct[pos]=++ctt;
        PathPoint[pos]=1;
        PathEdge[mkp(pos,fa[pos])]=1;
        PathEdge[mkp(fa[pos],pos)]=1;
        ll[pos]=PathId[mkp(fa[pos],pos)]>>1;
        rl[fa[pos]]=PathId[mkp(fa[pos],pos)]>>1;
        mapp[ll[pos]]=++tcnt;
    }
    ct[s]=++ctt;

    fa[s]=0;dijk2(s,fs,ds);
    fa[t]=0;dijk2(t,ft,dt);
    build(1,1,ecnt>>1);

    for(reg int i = 2; i <= ecnt; i+=2)
    {
        int a=e[i].from, b=e[i].to, val=e[i].val;
        if(!PathEdge[mkp(a,b)])
        {
            if(mapp[ll[ft[b]]] && mapp[ll[ft[b]]]<=mapp[rl[fs[a]]])update(1,mapp[ll[ft[b]]],mapp[rl[fs[a]]],ds[a]+dt[b]+val);
            if(mapp[ll[ft[a]]] && mapp[ll[ft[a]]]<=mapp[rl[fs[b]]])update(1,mapp[ll[ft[a]]],mapp[rl[fs[b]]],ds[b]+dt[a]+val);
        }
    }
    if(dis[t]>=INF)
    {
        for(;Q--;)
            printf("Infinity\n");
        return 0;
    }
    memset(print,0x7f,sizeof(print));
    ask(1);
    for(;Q--;)
    {
        int a=in(), b=in();
        if(!PathEdge[mkp(a,b)])printf("%lld\n",dis[t]);
        else
        {
            if(ct[a]<ct[b])swap(a,b);
            long long ans = print[mapp[ll[ft[b]]]];
            if(ans==INF)printf("Infinity\n");
            else printf("%lld\n",ans);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值