【BZOJ 3694】最短路 树链剖分+倍增

传送门
似乎是权限题

学妹有一种用智商解决的方法,比较玄学,代码量短很多,但是跑的慢一点点,可以不喜欢打线段树模板的人可以学习一下:)
chrt

Description

给出一个n个点m条边的无向图,n个点的编号从1~n,定义源点为1。定义最短路树如下:从源点1经过边集T到任意一点i有且仅有一条路径,且这条路径是整个图1到i的最短路径,边集T构成最短路树。 给出最短路树,求对于除了源点1外的每个点i,求最短路,要求不经过给出的最短路树上的1到i的路径的最后一条边。

Input

第一行包含两个数n和m,表示图中有n个点和m条边。
接下来m行,每行有四个数ai,bi,li,ti,表示图中第i条边连接ai和bi权值为li,ti为1表示这条边是最短路树上的边,ti为0表示不是最短路树上的边。
Output

输出n-1个数,第i个数表示从1到i+1的要求的最短路。无法到达输出-1。
Sample Input

5 9

3 1 3 1

1 4 2 1

2 1 6 0

2 3 4 0

5 2 3 0

3 2 2 1

5 3 1 1

3 5 2 0

4 5 4 0

Sample Output

6 7 8 5

HINT
对于100%的数据,n≤4000,m≤100000,1≤li≤100000
题解:
这个题目,首先按照题目给的建出最短路径树,若我们不经过最后的一条边那么我们一定是先往下走然后再往上走最后到点1;这儿如果是想不清楚就画出题目中的要求就自己画个图来辅助理解一下。
然后我们把非最短路上的边取出来,

假设有这样一条边 u - v 权值为c
那么我们计算出LCA(u,v) = t
我们从1到u,再从u经过这个边到v,然后在所有的从t-v上的边满足要求的到1的距离为d[u] + d[v] - d[x] + c;
我们只要对每一条边都这样不断更新每个点的距离最可以啦。

代码:

#include <iostream>
#include <cstdio>
#include <vector>

const int MAXN = 4005,MAXX = 100005,MAXD = 20,INF = 1e6;

using namespace std;

int N,M,e = 1,e1 = 1,dfn = 1,dx,dy,dt,ql,qr,data;
int head[MAXN],s[MAXN],anc[MAXN][MAXD+5],C[MAXN],Min[MAXN*20];

inline int min(int a,int b){return a < b ? a : b;}

struct SLPF{
    int size,top,son,fa,num,c,deep;
}F[MAXN];

struct node{
    int v,c,next;
}edge[10*MAXX];

struct Fnode{
    int u,v,c;
}edge1[10*MAXX];

inline int read(){
    int x = 0;char ch = getchar();
    while(ch < '0' || '9' < ch){ch = getchar();}
    while('0'<= ch && ch <='9'){x = x * 10 + ch - '0';ch = getchar();}
    return x;
}

inline void addedge(int u,int v,int c){
    edge[e] = (node){v,c,head[u]};head[u] = e++;
}

inline void init(){
    N = read();M = read();
    int u,v,c,k;
    
    for(int i = 1;i <= M;i++){
    
    u = read();v = read();c = read();k = read();
    
    if(k == 1) addedge(u,v,c),addedge(v,u,c);
    else edge1[e1++] = (Fnode){u,v,c};
    
    }
    
}

void dfs(int u){
    
    for(int i = 1;i <= MAXD;i++) anc[u][i] = anc[anc[u][i-1]][i-1];
    
    for(int i = head[u];i;i = edge[i].next)
    {
        int v = edge[i].v,c = edge[i].c;
        if(F[v].deep > F[u].deep){
            anc[v][0] = u;
            s[v] = s[u] + c;
            dfs(v);
        }
    }
    
}

void dfs_1(int u,int h){
    F[u].deep = h;F[u].size = 1;
    
    for(int i = head[u];i;i = edge[i].next){
        int v = edge[i].v;
        if(!F[v].deep){
            dfs_1(v,h+1);
            F[v].fa = u;
            F[u].size += F[v].size;
            if(F[v].size > F[F[u].son].size)
            F[u].son = v;
        }
    }
    
}

void dfs_2(int u,int top){
    F[u].top = top;
    
    if(F[u].son){
        F[ F[u].son ].num = dfn++;
        dfs_2(F[u].son,top);
    }
    
    for(int i = head[u];i;i = edge[i].next){
        int v = edge[i].v;
        if(!F[v].num){
        F[v].num = dfn++;
        dfs_2(v,v);
        }
    }
}

inline void swim(int &u,int h){
    for(int i = 0;h;i++){
        
        if(h&1){u = anc[u][i];}
        h >>= 1;
    }
}

inline int lca(int x,int y)
{
    
    if(F[x].deep < F[y].deep) swap(x,y);
    
    swim(x,F[x].deep - F[y].deep);
    
    for(int i = MAXD;i >= 0;i--)
        if(anc[x][i] != anc[y][i]){
        
        x = anc[x][i];
        y = anc[y][i];
    }
    
    if(x != y) return anc[x][0];
    else return x;
}

inline void maintain(int o){
Min[o*2] = min(Min[o*2],Min[o]);
Min[o*2+1] = min(Min[o*2+1],Min[o]);
}

void update(int o,int L,int R)
{
    int Mid = (L + R) / 2;
    if(ql <= L && R <= qr){Min[o] = min(Min[o],data);return;}
    if(ql <= Mid) update(o*2,L,Mid);
    if(qr > Mid) update(o*2+1,Mid+1,R);
}

void update_INF(int o,int L,int R)
{
    int Mid = (L + R) / 2;
    Min[o] = INF;
    if(L == R) return;
    update_INF(o*2,L,Mid);
    update_INF(o*2+1,Mid+1,R);
}

int print(int o,int L,int R){
    int Mid = (L + R) / 2;
    maintain(o);
    if(L == R) {return Min[o] == INF ? -1 : Min[o];}
    if(ql <= Mid) return print(o*2,L,Mid);
    else return print(o*2+1,Mid+1,R);
}

inline void query(int x,int y)
{
    
    while(F[x].top != F[y].top){
        if( F[F[x].top].deep > F[F[y].top].deep ){
            ql = F[F[x].top].num;qr = F[x].num;
            update(1,1,N);
            x = F[F[x].top].fa;
        }
        
        else {
            ql = F[F[y].top].num;qr = F[y].num;
            update(1,1,N);
            y = F[F[y].top].fa;
        }
    }
    
    if(F[x].deep < F[y].deep){
        ql = F[F[x].son].num;qr = F[y].num;
        update(1,1,N);
    }
    
    else{
        ql = F[F[y].son].num;qr = F[x].num;
        update(1,1,N);
    }
}

int main()
{
    init();
    
    dfs_1(1,1);
    
    F[1].num = dfn++;
    
    dfs_2(1,1);
    
    dfs(1);
    
    update_INF(1,1,N);
    
    for(int i = 1;i < e1;i++)
    {
        int u = edge1[i].u,v = edge1[i].v,c = edge1[i].c;
        
        int t = lca(u,v);
        data = s[u] + s[v] + c;
        query(t,v);
        query(t,u);
        
    }
    
    for(int i = 2;i <= N;i++)
    {
        ql = F[i].num;
        int ans = print(1,1,N);
        printf("%d ",ans == -1 ? -1 : ans - s[i]);
    }
    
    return 0;
} 
Last modification:October 1st, 2018 at 08:19 am
If you think my article is useful to you, please feel free to appreciate

Leave a Comment