zoukankan      html  css  js  c++  java
  • [HNOI2014] 道路堵塞

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

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

    如果删掉的是非最短路边,那么显然毫无影响
    如果删掉的是最短路边,那么我们倒过来,考虑这个时候每条非最短路边的贡献。对于一条非最短路边 ((u,v)) ,我们很容易得到一定包含它的最短路一定是满足 (1 o x o u o v o y o 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
    ",chk(seg::query(1,1,len,use[t1])));
            else
                printf("%d
    ",chk(gs.d[n]));
        }
    }
    
    
  • 相关阅读:
    video 标签在微信浏览器的问题解决方法
    微信朋友圈分享之自定义网页按钮分享
    巧用weui.topTips验证数据
    巧用weui.gallery(),点击图片后预览图片
    巧用ajax请求服务器加载数据列表时提示loading
    页面间固定参数,通过cookie传值
    手机端页面下拉加载数据的笨办法--点击按钮添加数据
    LeetCode 41 First Missing Positive(找到数组中第一个丢失的正数)
    LeetCode 40 Combination Sum II(数组中求和等于target的所有组合)
    LeetCode 39 Combination Sum(满足求和等于target的所有组合)
  • 原文地址:https://www.cnblogs.com/mollnn/p/11684816.html
Copyright © 2011-2022 走看看