zoukankan      html  css  js  c++  java
  • SDOI 2017 天才黑客

    /*
    根据claris的  博客以及 beginend 的博客来写的
    
    
    首先考虑如何求出最短路  可以从样例看出  路径是从边走到边的, 所以我们将边看作点  有共同端点的两边之间
    互相连边, 边权为lcp。 这条边自己的花费计算要拆点, 拆成的两个点之间连原来的花费  这样跑最短路就可以啦
    
    然而这样的做法有问题, 考虑边数最大可能是M^2切要求M^2个lca  显然不行
    
    这里采用claris巨佬的方法
    
    /*********beginend的题解*******
    假如现在有n个节点a[1..n]要两两求lca,我们将其按dfs序排序,设h[i]=dep[lca(a[i],a[i+1])],根据后缀数组height数组的性质不难得到dep[lca(a[i],a[j])]=min(h[i]..h[j-1])。
    那么我们可以枚举中间的每个h[i],i两边的点就可以至少花费h[i]的费用来互相访问。我们只要建立前缀虚点和后缀虚电来优化连边即刻。
    
    */
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<iostream>
    #define M 100200
    #define ll long long
    #define id1(x) x * 2 - 1
    #define id2(x) x * 2
    using namespace std;
    int n,m, k, deep[M], dfn[M], size[M], fa[M], son[M], top[M], ls[M], inh[M], outh[M], inx[M], outx[M], pst[M];
    int  inp[M], outp[M], ins[M], outs[M], sz, head[M * 10], cnt, tm, to[M << 5], nxt[M << 5], ver[M << 5], a[M];
    ll dis[M * 10];
    bool vis[M * 10], in[M], out[M];
    int read() {
        int nm = 0, f = 1;
        char c = getchar();
        for(; !isdigit(c); c = getchar()) if(c == '-') f = -1;
        for(; isdigit(c); c = getchar()) nm = nm * 10 + c -'0';
        return nm * f;
    }
    
    void init() {
        cnt = tm = 0;
        memset(head, 0, sizeof(head));
        memset(ls, 0, sizeof(ls));
        memset(inh, 0, sizeof(inh));
        memset(outh, 0, sizeof(outh));
        memset(son, 0, sizeof(son));
    }
    
    void push(int vi, int vj, int wei) {
        cnt++, to[cnt] = vj, ver[cnt] = wei, nxt[cnt] = head[vi], head[vi] = cnt;
        if(cnt >= (M << 5)) {
            puts("gg");
            exit(0);
        }
    }
    
    void add(int vi, int vj) {
        cnt++, to[cnt] = vj, nxt[cnt] = ls[vi], ls[vi] = cnt;
    }
    
    void dfs1(int now) {
        size[now] = 1;
        int maxx = 0;
        for(int i = ls[now]; i; i = nxt[i]) {
            int vj = to[i];
            deep[vj] = deep[now] + 1;
            fa[vj] = now;
            dfs1(vj);
            size[now] += size[vj];
            if(size[vj] > maxx) maxx = size[vj], son[now] = vj;
        }
    }
    
    void dfs2(int now) {
        dfn[now] = ++tm;
        if(son[now]) {
            top[son[now]] = top[now];
            dfs2(son[now]);
        }
        for(int i = ls[now]; i; i = nxt[i]) {
            int vj = to[i];
            if(vj == son[now]) continue;
            top[vj] = vj;
            dfs2(vj);
        }
    }
    
    void spfa() {
        for(int i = 1; i <= sz; i++) dis[i] = 10000000000000000ll;
        queue<int>q;
        q.push(0);
        dis[0] = 0;
        vis[0] = true;
        while(!q.empty()) {
            int op = q.front();
            q.pop();
            vis[op] = false;
            for(int i = head[op]; i; i = nxt[i]) {
                int vj = to[i];
                if(dis[vj] > dis[op] + ver[i]) {
                    dis[vj] = dis[op] + ver[i];
                    if(!vis[vj]) {
                        vis[vj] = true;
                        q.push(vj);
                    }
                }
            }
        }
    }
    
    void dijk() {
        for(int i = 0; i <= sz; i++) dis[i] = 10000000000000000ll, vis[i] = 0;
        dis[0] = 0;
        priority_queue<pair<int,int> > q;
        q.push(make_pair(0,0));
        while(!q.empty()) {
            pair<int, int> now = q.top();
            q.pop();
            while(!q.empty() && vis[now.second]) now = q.top(), q.pop();
            if(vis[now.second]) break;
            int op = now.second;
            vis[op] = true;
            for(int i = head[op]; i; i = nxt[i]) {
                int vj = to[i];
                if(dis[vj] > dis[op] + ver[i]) {
                    dis[vj] = dis[op] + ver[i];
                    q.push(make_pair(-dis[vj],vj));
                }
            }
        }
    }
    
    int lca(int x, int y) {
        while(top[x] != top[y]) {
            if(deep[top[x]] < deep[top[y]]) swap(x, y);
            x = fa[top[x]];
        }
        return deep[x] < deep[y] ? x : y;
    }
    
    bool cmp(int x, int y) {
        return dfn[pst[x]] < dfn[pst[y]];
    }
    
    int main() {
        int T = read();
        while(T--) {
            init();
            n = read(), m = read(), k = read();
            sz = m * 2;
            for(int i = 1; i <= m; i++) {
                int vi = read(), vj = read(), wei = read();
                pst[i] = read();
                push(id1(i), id2(i), wei);
                inx[i] = inh[vj], inh[vj] = i, outx[i] = outh[vi], outh[vi] = i;
            }
            for(int i = 1; i < k; i++) {
                int vi = read(), vj = read();
                read();
                add(vi, vj);
            }
            dfs1(1), top[1] = fa[1] = 1;
            dfs2(1);
            for(int x = 1; x <= n; x++) {
                int a1 = 0;
                for(int i = inh[x]; i; i = inx[i]) a[++a1] = i, in[i] = 1;
                for(int i = outh[x]; i; i = outx[i]) a[++a1] = i, out[i] = 1;
                sort(a + 1, a + a1 + 1, cmp);
                for(int i = 1; i <= a1; i++) {
                    inp[i] = ++sz;
                    outp[i] = ++sz;
                    if(in[a[i]]) push(id2(a[i]), inp[i], 0);
                    if(out[a[i]]) push(outp[i], id1(a[i]), 0);
                    if(i > 1) push(inp[i - 1], inp[i], 0), push(outp[i - 1], outp[i], 0);
                }
                for(int i = a1; i >= 1; i--) {
                    ins[i] = ++sz;
                    outs[i] = ++sz;
                    if(in[a[i]]) push(id2(a[i]), ins[i], 0);
                    if(out[a[i]]) push(outs[i], id1(a[i]), 0);
                    if(i < a1) push(ins[i + 1], ins[i], 0), push(outs[i + 1], outs[i], 0);
                }
                for(int i = 1; i < a1; i++) {
                    int lc = deep[lca(pst[a[i]], pst[a[i + 1]])];
                    push(inp[i], outp[i + 1], lc);
                    push(ins[i + 1], outs[i], lc);
                }
                for(int i = 1; i <= a1; i++) in[a[i]] = out[a[i]] = 0;
            }
            for(int i = outh[1]; i; i = outx[i]) push(0, id1(i), 0);
            //spfa();
            dijk();
            for(int x = 2; x <= n; x++) {
                ll mn = 10000000000000000ll;
                for(int i = inh[x]; i; i = inx[i]) mn = min(mn, dis[id2(i)]);
                cout << mn << "
    ";
            }
        }
        return 0;
    }
    
    /*
    2
    4 4 6
    1 2 2 5
    2 3 2 5
    2 4 1 6
    4 2 1 6
    1 2 1
    2 3 1
    3 4 1
    4 5 2
    1 6 2
    
    4 4 6
    1 2 2 5
    2 3 2 5
    2 4 1 6
    4 2 1 6
    1 2 1
    2 3 1
    3 4 1
    4 5 2
    1 6 2
    
    */
  • 相关阅读:
    poj3067 Japan(树状数组)
    Codeforces 482C Game with Strings(dp+概率)
    LeetCode -- 推断链表中是否有环
    螺旋矩阵——正逆序
    POJ 3905 Perfect Election(2-sat)
    设计模式 之 桥接
    Codeforces Round #257 (Div. 2)
    [LeetCode][Java] Minimum Window Substring
    Unity特殊目录和脚本编译顺序
    jQuery插件 -- Cookie插件
  • 原文地址:https://www.cnblogs.com/luoyibujue/p/9240316.html
Copyright © 2011-2022 走看看