BZOJ 1576: [Usaco2009 Jan]安全路经Travel【最短路树】【树链剖分】

Description

这里写图片描述

题解

复习一下树链剖分。

最短路树,非树边与树边形成的环上,除了LCA,其他的点都可以经过非树边,从所有答案中刷最小值,用树链剖分维护。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define maxn 100006
#define maxe 200006
using namespace std;
inline char nc(){
    static char buf[100000],*i=buf,*j=buf;
    return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;
}
inline int _read(){
    char ch=nc();int sum=0;
    while(!(ch>='0'&&ch<='9'))ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum;
}
int n,e,N,tem,tot[2],dep[maxn],id[maxn],dis[maxn],fa[maxn],top[maxn],num[maxn],H_son[maxn],
    lnk[2][maxn],son[2][maxe*2],nxt[2][maxe*2],w[2][maxe*2];
bool vis[maxn];
struct point{
    int x,s;
    bool operator <(const point&b)const{return s>b.s;}
};
priority_queue <point > heap;
struct side{
    int x,y,w;
}a[maxe];
struct data{
    int l,r,tag,x;
    void add(int k){
        tag=min(tag,k);x=min(x,k);
    }
}tree[maxn*4];
void add(int p,int x,int y,int z){
    nxt[p][++tot[p]]=lnk[p][x];son[p][tot[p]]=y;w[p][tot[p]]=z;lnk[p][x]=tot[p];
}
void dij(){
    memset(vis,1,sizeof(vis));memset(dis,63,sizeof(dis));
    dis[1]=0;point p;p.x=1;p.s=0;heap.push(p);
    for(int i=1;i<=n;i++){
        while(!vis[heap.top().x])heap.pop();
        p=heap.top();heap.pop();
        vis[p.x]=0;
        for(int j=lnk[0][p.x];j;j=nxt[0][j]) if(vis[son[0][j]]&&dis[p.x]+w[0][j]<dis[son[0][j]]){
            dis[son[0][j]]=dis[p.x]+w[0][j];fa[son[0][j]]=p.x;
            point pp;pp.x=son[0][j];pp.s=dis[son[0][j]];heap.push(pp);
        }
    }
    for(int i=2;i<=n;i++)add(1,fa[i],i,0);
}
void dfs1(int x){
    vis[x]=0;num[x]=1;
    for(int j=lnk[1][x];j;j=nxt[1][j]) if(vis[son[1][j]]){
        dep[son[1][j]]=dep[x]+1;
        dfs1(son[1][j]);
        if(num[son[1][j]]>num[H_son[x]])H_son[x]=son[1][j];
        num[x]+=num[son[1][j]];
    }
}
void build(int p,int l,int r){
    tree[p].l=l;tree[p].r=r;tree[p].tag=tree[p].x=1e9;
    if(l>=r)return;
    int mid=(l+r)>>1;
    build(p<<1,l,mid);build(p<<1|1,mid+1,r);
}
void pushdown(int p){
    if(tree[p].tag==1e9)return;
    tree[p<<1].add(tree[p].tag);tree[p<<1|1].add(tree[p].tag);
    tree[p].tag=1e9;
}
void update(int p,int l,int r,int k){
    if(tree[p].l>r||tree[p].r<l)return;
    if(l<=tree[p].l&&r>=tree[p].r){
        tree[p].add(k);return;
    }
    pushdown(p);
    update(p<<1,l,r,k);update(p<<1|1,l,r,k);
    tree[p].x=min(tree[p<<1].x,tree[p<<1|1].x);
}
int query(int p,int k){
    if(tree[p].l>k||tree[p].r<k)return 1e9;
    if(tree[p].l==tree[p].r)return tree[p].x;
    pushdown(p);
    return min(query(p<<1,k),query(p<<1|1,k));
}
void dfs2(int x,int y){
    vis[x]=0;id[x]=++tem;top[x]=y;
    if(H_son[x]){
        fa[H_son[x]]=x;
        dfs2(H_son[x],y);
    }
    for(int j=lnk[1][x];j;j=nxt[1][j])if(vis[son[1][j]]){
        fa[son[1][j]]=x;
        dfs2(son[1][j],son[1][j]);
    }
}
void change(int x,int y,int k){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        update(1,id[top[x]],id[x],k);
        x=fa[top[x]];
    }
    if(x==y)return;
    if(dep[x]>dep[y])swap(x,y);
    update(1,id[H_son[x]],id[y],k);
}
int main(){
    freopen("travel.in","r",stdin);
    freopen("travel.out","w",stdout);
    n=_read();e=_read();
    for(int i=1,x,y,z;i<=e;i++)x=_read(),y=_read(),z=_read(),add(0,x,y,z),add(0,y,x,z);
    dij();
    for(int i=1;i<=n;i++)
     for(int j=lnk[0][i];j;j=nxt[0][j]) if((j&1)&&fa[i]!=son[0][j]&&fa[son[0][j]]!=i){
        ++N;a[N].x=i;a[N].y=son[0][j];a[N].w=w[0][j]+dis[a[N].x]+dis[a[N].y];
     }
    memset(vis,1,sizeof(vis));dep[1]=1;
    dfs1(1);
    memset(vis,1,sizeof(vis));
    build(1,1,n);dfs2(1,1);
    for(int i=1;i<=N;i++)change(a[i].x,a[i].y,a[i].w);
    for(int i=2;i<=n;i++){
        int t=query(1,id[i]);
        if(t==1e9)printf("-1\n");
             else printf("%d\n",t-dis[i]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/fyoier/article/details/78430298