bzoj 2725 [Violet 6]故乡的梦


无向图,给定S和T,多次询问在删除某条边时两点间最短路

我的SPFA被卡了=.=。我们对所有不在最短路径的上的边 ,设它的起点为u 终点为v。那么对于这条边,包含该边的最优的S到T路径就应该是 S-S1-u-v-T1-T 其中S1,T1表示最短路径上的两个点。那么这样的一条最短路可以再S1-T1中某条边被删除时使用,我们用线段树维护这一过程 QWQ 数组开多了有点晕啊

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
const int maxn=400000+10;
typedef long long LL;
struct tree{int l,r;LL s,lazy;}t[maxn<<2];
struct node{int to,next;LL len;int fr;bool o;}table[maxn<<1];
int tot=1,head[maxn];
void add(int a,int b,int c){table[++tot]=(node){b,head[a],c,a};head[a]=tot;}
int n,m,S,T,Q;
char s[1<<25];
inline long long read()
{
    static char *c=s;
    if(c==s) fread(c,1,1<<25,stdin);
    long long u=0;
    while(*c<48) ++c;
    while(*c>32) u=u*10+*c++-48;
    return u;
}
int pre[maxn],pos[maxn],cnt;
LL f[maxn][2];
bool v[maxn],use[maxn],iskeypoint[maxn];
typedef pair<LL,int>Pair;
void spfa()
{
    for(int i=1;i<=n;i++) f[i][0]=1e14;
    f[S][0]=0;
    priority_queue<Pair,vector<Pair>,greater<Pair> >Q;
    Q.push(make_pair(0,S));
    while(!Q.empty())
    {
        Pair top=Q.top();
        Q.pop();
        int x=top.second;
        if(v[x]) continue;
        for(int i=head[x];i;i=table[i].next)
        if(f[table[i].to][0]>f[x][0]+table[i].len&&!v[table[i].to])
        {
            pre[table[i].to]=i;
            f[table[i].to][0]=f[x][0]+table[i].len;
            Q.push(make_pair(f[table[i].to][0],table[i].to));
        }
    }
}
int ans[maxn][2],num[maxn];
void QWQ(int k)
{
    memset(v,0,sizeof v);
    for(int i=1;i<=n;i++) f[i][k]=1e14;
    priority_queue<Pair,vector<Pair>,greater<Pair> >Q;
    if(k==0) f[S][0]=0,Q.push(make_pair(0,S));
    else f[T][1]=0,Q.push(make_pair(0,T));
    while(!Q.empty())
    {
        Pair top=Q.top();
        Q.pop();
        int x=top.second;
        if(v[x]) continue;
        for(int i=head[x];i;i=table[i].next)
        if(f[table[i].to][k]>f[x][k]+table[i].len&&!v[table[i].to])
        {
            if(iskeypoint[table[i].to]&&iskeypoint[x]) ans[table[i].to][k]=i;
            else ans[table[i].to][k]=ans[x][k];
            f[table[i].to][k]=f[x][k]+table[i].len;
            Q.push(make_pair(f[table[i].to][k],table[i].to));
        }
    }
}
void maketree(int x,int l,int r)
{
    t[x].l=l; t[x].r=r;
    t[x].lazy=t[x].s=1e14;
    if(l==r) return ;
    int mid=l+r>>1;
    maketree(x<<1,l,mid);
    maketree(x<<1|1,mid+1,r);
    t[x].s=min(t[x<<1].s,t[x<<1|1].s);
}
void change(int x,int l,int r,LL tar)
{
    if(t[x].l==l&&t[x].r==r) 
    {
        t[x].lazy=min(t[x].lazy,tar);
        return ;
    }
    int mid=t[x].l+t[x].r>>1;
    int lc=x<<1,rc=x<<1|1;
    if(r<=mid) change(x<<1,l,r,tar);
    else if(l>mid) change(x<<1|1,l,r,tar);
    else change(x<<1,l,mid,tar),change(x<<1|1,mid+1,r,tar);
}
LL res;
void search(int x,int pos)
{
    res=min(res,t[x].lazy);
    if(t[x].l==t[x].r) return ;
    int mid=t[x].l+t[x].r>>1;
    int lc=x<<1,rc=x<<1|1;
    if(pos<=mid) return search(x<<1,pos);
    return search(x<<1|1,pos);
}
int main()
{
    scanf("%d%d",&n,&m);
    int x,y,c;
    for(int i=1;i<=m;i++)
    {
        x=read(); y=read(); c=read();
        add(x,y,c); add(y,x,c);
    }
    S=read(); T=read();
    spfa();
    int hh=T;
    while(hh)
    {
        if(pre[hh]) pos[++cnt]=pre[hh];
        use[pre[hh]]=1;
        iskeypoint[hh]=1;
        table[pre[hh]].o=1;
        hh=table[pre[hh]].fr;
    }
    for(int i=1;i<=cnt;i++) num[i]=pos[i];
    for(int i=1;i<=cnt;i++) pos[i]=num[cnt-i+1];
    memset(num,0,sizeof num);
    for(int i=1;i<=cnt;i++) num[pos[i]]=i;
    for(int i=1;i<=n;i++) ans[i][0]=-1,ans[i][1]=tot+1;
    QWQ(0); QWQ(1);
    maketree(1,1,cnt);
    for(int i=1;i<=tot;i++)
    if(!use[i])
    {
        int l=ans[table[i].fr][0],r=ans[table[i].to][1];
        int pos1,pos2;
        if(l==-1) pos1=1; else pos1=num[l]+1;
        if(r==tot+1) pos2=cnt; else pos2=num[r^1]-1;
        if(pos1<=pos2) change(1,pos1,pos2,table[i].len+f[table[i].fr][0]+f[table[i].to][1]);
    }
    Q=read();
    while(Q--)
    {
        x=read(); y=read();
        int pos;
        if((table[pre[x]].fr==y||table[pre[y]].fr==x)&&iskeypoint[x]&&iskeypoint[y]) 
        {
            if(table[pre[y]].fr==x) pos=num[pre[y]];
            else pos=num[pre[x]];
            res=1e14;
            search(1,pos);
            if(res>=1e14) puts("Infinity");
            else printf("%lld\n",res);
        }
        else printf("%lld\n",f[T][0]);
    }
    return 0;
}



评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值