其他分享
首页 > 其他分享> > [HNOI2014] 道路堵塞 - 最短路,线段树

[HNOI2014] 道路堵塞 - 最短路,线段树

作者:互联网

对不起对不起,辣鸡蒟蒻又来用核弹打蚊子了

完全ignore了题目给出的最短路,手工搞出一个最短路,发现对答案没什么影响
所以干脆转化为经典问题:每次询问删掉一条边后的最短路

如果删掉的是非最短路边,那么显然毫无影响
如果删掉的是最短路边,那么我们倒过来,考虑这个时候每条非最短路边的贡献。对于一条非最短路边 \((u,v)\) ,我们很容易得到一定包含它的最短路一定是满足 \(1 \to x \to u \to v \to y \to n\) 这样的结构,其中 \(x,y\) 都在选定的最短路上,那么只要删除的是最短路上 \(x \sim y\) 之间的边,这个贡献就是存在的。

考虑如何求出对 \((u,v)\) 的 \(x,y\) ,跑完最短路后搞出最短路径树,那么最短路显然是最短路径树的一条链。对这条链上任意一个点 \(p\) ,对它所有不在链上的儿子 \(q\) ,我们将每一个 \(q\) 的子树都打上 \(p\) 标记,表示从 \(1\) 到这些点的最短路在 \(p\) 点与选定的 \(1 \sim n\) 最短路分开

因此我们维护删掉最短路上每条边时的答案,这是一个序列。枚举每条非最短路边去计算它的贡献与贡献范围,贡献范围内的每个位置对它的贡献值取Min,线段树标记永久化维护即可。

#include <bits/stdc++.h>
using namespace std;

const int N = 400005;

int cnt = 0;

struct item {
    int v,w,id;
};

struct graph {
    vector <item> g[N];
    vector <int> tree[N];
    int d[N],v[N],c[N],fa[N],fid[N];

    void make(int t1,int t2,int t3,int t4) {
        g[t1].push_back((item) {
            t2,t3,t4
        });
    }

    void sp(int v0,int n) {
        memset(d,0x3f,sizeof d);
        memset(v,0x00,sizeof v);
        priority_queue <pair<int,int> > q;
        d[v0]=0;
        q.push(make_pair(0,v0));
        while(!q.empty()) {
            pair<int,int> p=q.top();
            int dis=-p.first, pos=p.second;
            q.pop();
            v[pos]=1;
            for(int i=0;i<g[pos].size();i++) {
                int x=g[pos][i].v,y=g[pos][i].w,z=g[pos][i].id;
                if(d[x]>d[pos]+y) {
                    d[x]=d[pos]+y;
                    fa[x]=pos;
                    fid[x]=z;
                    if(!v[x]) q.push(make_pair(-d[x],x));
                }
            }
        }
        for(int i=1; i<=n; i++) {
            if(fa[i])
                tree[fa[i]].push_back(i);
            c[i]=i;
        }
    }

    void dfs(int p,int x) {
        c[p]=x;
        for(int i=0; i<tree[p].size(); i++) {
            dfs(tree[p][i],x);
        }
    }

    void gen(int s,int t) {
        for(int p=t,q; q=fa[p]; p=q) {
            for(int i=0; i<tree[q].size(); i++) {
                if(tree[q][i]!=p) {
                    dfs(tree[q][i],q);
                }
            }
        }
    }

} gs,gt;

struct edge {
    int u,v,w;
};

edge e[N];
int n,m,q,t1,t2,t3,t4,use[N],sid[N];

vector <int> sp;

namespace seg {
int a[N<<2];
void reset() {
    memset(a,0x3f,sizeof a);
}
void modify(int p,int l,int r,int ql,int qr,int x) {
    if(l>qr||r<ql)
        return;
    if(l>=ql && r<=qr) {
        a[p]=min(a[p],x);
    } else {
        modify(p*2,l,(l+r)/2,ql,qr,x);
        modify(p*2+1,(l+r)/2+1,r,ql,qr,x);
    }
}
int query(int p,int l,int r,int pos) {
    if(l==r) {
        return a[p];
    } else {
        if(pos<=(l+r)/2) {
            return min(query(p*2,l,(l+r)/2,pos), a[p]);
        } else {
            return min(query(p*2+1,(l+r)/2+1,r,pos), a[p]);
        }
    }
}
} // namespace seg

int chk(int x)
{
    if(x>=0x3f3f3f3f) return -1;
    else return x;
}

signed main() {
    seg::reset();

    scanf("%d%d%d",&n,&m,&q);
    for(int i=1; i<=m; i++) {
        scanf("%d%d%d",&t1,&t2,&t3);
        if(t2==1) t2=t1;
        if(t1==n) t1=t2;
        e[i] = (edge) {
            t1,t2,t3
        };
        gs.make(t1,t2,t3,i);
        gt.make(t2,t1,t3,i);
    }

    gs.sp(1,n);
    gt.sp(n,n);
    gs.gen(1,n);
    gt.gen(n,1);

    int ind = 0;
    for(int i=1; gt.fa[i]; i=gt.fa[i]) {
        sp.push_back(gt.fid[i]);
        use[gt.fid[i]]=++ind;
    }
    sid[1]=0;
    for(int i=0; i<sp.size(); i++) {
        sid[e[sp[i]].v]=i+1;
    }
    int len=sp.size();
    for(int i=1; i<=m; i++) {
        if(use[i]==0) {
            int u=e[i].u, v=e[i].v, w=e[i].w;
            seg::modify(1,1,len,sid[gs.c[u]]+1,sid[gt.c[v]],gs.d[u]+gt.d[v]+w);
        }
    }

    for(int i=1; i<=q; i++) {
        scanf("%d",&t1);
        if(use[t1])
            printf("%d\n",chk(seg::query(1,1,len,use[t1])));
        else
            printf("%d\n",chk(gs.d[n]));
    }
}

标签:int,线段,删掉,pos,贡献,路边,HNOI2014,短路
来源: https://www.cnblogs.com/mollnn/p/11684816.html