BZOJ2125 最短路(圆方树)

题目链接

思路:
             关于静态仙人掌的问题,建立出圆方树比较好求解。求出来之后处理每个圆点方点的情况,原来的是树边直接处理,环边的话方点连向环上每个圆点一条边,权值为每个节点到环的父亲节点的最短距离。然后倍增预处理,查询的时候,如果 lca l c a 是圆点直接输出,否则两个点是环上的点,处理他们在环上的最短距离即可。
             为啥我的代码都这么慢啊。。。加了输入输出挂还900ms。。别人的什么都不做都400ms。。。

#include<bits/stdc++.h>
typedef long long ll;
const int maxn = 1e5 + 10;
using namespace std;

struct edge {
    int u, v, cost;
    edge(int u = 0, int v = 0, int cost = 0) : u(u), v(v), cost(cost) {}
};
int n, m, T, kase = 1, q;
vector<int> G[maxn], bcc[maxn], w[maxn];
int dp[maxn][2], dfn[maxn], dfs_clock, tot;
int pre[maxn], bccno[maxn], bcc_cnt, stk[maxn][2];
vector<int> et[maxn], ew[maxn];
int rec_cost[maxn], deep[maxn], ds[maxn];
stack<edge> S;
const int hash_size = 1e6 + 10;
int head[hash_size], nxt[hash_size], vt[hash_size], tt[hash_size], key[hash_size], top;
int anc[maxn][15], cost[maxn][15];

void insert(int u, int t, int val) {
    int x = u * (maxn / 10) + t;
    x = x % hash_size;
    nxt[top] = head[x];
    head[x] = top; 
    vt[top] = u;
    tt[top] = t;
    key[top] = val;
    top++;
}

int ask(int u, int t) {
    int x = u * (maxn / 10) + t;
    x = x % hash_size;
    int nn = head[x];
    while(~nn) { if(vt[nn] == u && tt[nn] == t) return key[nn]; nn = nxt[nn]; }
    return 0;
}

int dfs(int u, int fa) { 
    int lowu = pre[u] = ++dfs_clock, child = 0;
    for(int i = 0; i < G[u].size(); i++) {
        int v = G[u][i], co = w[u][i];
        edge e = edge(u, v, co);
        if(!pre[v]) {
            S.push(e); child++;
            int lowv = dfs(v, u);
            lowu = min(lowu, lowv);
            if(lowv >= pre[u]) {
                bcc_cnt++; bcc[bcc_cnt].clear();
                int tot_dis = 0, cnt = 0;
                while(1) {
                    edge x = S.top(); S.pop();
                    rec_cost[cnt++] = x.cost;
                    tot_dis += x.cost;
                    if(bccno[x.v] != bcc_cnt) { bcc[bcc_cnt].push_back(x.v); bccno[x.v] = bcc_cnt; } 
                    if(bccno[x.u] != bcc_cnt) { bcc[bcc_cnt].push_back(x.u); bccno[x.u] = bcc_cnt; }
                    if(x.u == u && x.v == v) break;
                }
                if(bcc[bcc_cnt].size() == 2) {
                    et[u].push_back(v);  //树边
                    et[v].push_back(u);
                    ew[u].push_back(co);
                    ew[v].push_back(co); 
                } else {
                    tot++; int dis = 0; ds[tot] = tot_dis;
                    for(int i = 0; i < bcc[bcc_cnt].size(); i++) {
                        int v = bcc[bcc_cnt][i];
                        et[v].push_back(tot);
                        et[tot].push_back(v);
                        if(!i) {
                            ew[v].push_back(0); ew[tot].push_back(0);
                            insert(v, tot, dis);
                        } else {
                            insert(v, tot, dis);
                            int min_dis = min(dis, tot_dis - dis);
                            ew[v].push_back(min_dis);
                            ew[tot].push_back(min_dis);
                        }
                        dis += rec_cost[i];
                    }
                }
            }
        } else if(pre[v] < pre[u] && v != fa) {
            S.push(e); lowu = min(lowu, pre[v]);
        }
    }
    return lowu;
}

const int MAX = 10000;
char buf[MAX], *ps = buf, *pe = buf + 1;
inline void rnext() {
    if(++ps == pe) pe = (ps = buf) + fread(buf, sizeof(char), sizeof(buf) / sizeof(char), stdin);
}
template <class T>
inline bool in(T &ans) {
    ans = 0;
    T f = 1;
    if(ps == pe) return false;//EOF
    do{
        rnext();
        if('-' == *ps) f = -1;
    } while(!isdigit(*ps) && ps != pe);
    if(ps == pe) return false;//EOF
    do {
        ans = (ans<<1)+(ans<<3)+*ps-48;
        rnext();
    } while(isdigit(*ps) && ps != pe);
    ans *= f;
    return true;
}

void DFS(int x, int fa, int co, int d) {
    anc[x][0] = fa;  cost[x][0] = co; deep[x] = d;
    for(int i = 1; i < 15; i++) {
        int t = anc[x][i - 1];
        if(~t) { anc[x][i] = anc[t][i - 1]; cost[x][i] = cost[x][i - 1] + cost[t][i - 1]; }
        else break;
    }
    for(int i = 0; i < et[x].size(); i++) {
        int v = et[x][i];
        int c = ew[x][i];
        if(v != fa) DFS(v, x, c, d + 1);
    }
}

inline int query(int x, int y) {
    int ans = 0;
    if(deep[x] < deep[y]) swap(x, y);
    for(int i = 14; i >= 0; i--) {
        if(deep[x] - (1 << i) < deep[y]) continue;
        ans += cost[x][i]; x = anc[x][i];
    }
    if(x == y) return ans;
    for(int i = 14; i >= 0; i--) {
        if(anc[x][i] == anc[y][i]) continue;
        ans += cost[x][i]; ans += cost[y][i];
        x = anc[x][i]; y = anc[y][i];
    }
    if(anc[x][0] > n) {
        int px = anc[x][0], tot_dis = ds[px];
        int now_dis = abs(ask(x, px) - ask(y, px));
        ans += min(now_dis, tot_dis - now_dis);
    } else ans += cost[x][0] + cost[y][0];
    return ans;
}

char bufout[MAX], outtmp[50],*pout = bufout, *pend = bufout + MAX;
inline void write() {
    fwrite(bufout, sizeof(char), pout - bufout, stdout);
    pout = bufout;
}
inline void out_char(char c) { *(pout++) = c; if(pout == pend) write(); }
inline void out_str(char *s) {
    while(*s) {
        *(pout++) = *(s++);
        if(pout == pend) write();
    }
}
template <class T>
inline void out_int(T x) {
    if(!x) {
        out_char('0');
        return;
    }
    if(x < 0) x = -x,out_char('-');
    int len = 0;
    while(x) {
        outtmp[len++] = x%10+48;
        x /= 10;
    }
    outtmp[len] = 0;
    for(int i = 0, j = len - 1; i < j; i++,j--) swap(outtmp[i],outtmp[j]);
    out_str(outtmp);
}

int main() {
//    ios::sync_with_stdio(0);
//    freopen("in.txt", "r", stdin);
//    freopen("wa.txt", "w", stdout); 
    memset(head, -1, sizeof head);
    memset(nxt, -1, sizeof nxt);
//    cin >> n >> m >> q;
    in(n); in(m); in(q);
    for(int i = 1; i <= m; i++) {
        int u, v, c; //cin >> u >> v >> c;
        in(u); in(v); in(c);
        G[u].push_back(v); 
        w[u].push_back(c);
        G[v].push_back(u); 
        w[v].push_back(c);
    }
    tot = n;
    memset(anc, -1, sizeof anc);
    dfs(1, -1); DFS(1, -1, 0, 1);
    while(q--) {
        int u, v;
        //cin >> u >> v;
        in(u); in(v);
        int ans = query(u, v);
        //cout << ans << endl;
        //printf("%d\n", ans);
        out_int(ans); out_char('\n');
    }
    write();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值