码迷,mamicode.com
首页 > 其他好文 > 详细

习题:树上的最短路(树链剖分优化建图)

时间:2020-01-28 12:35:56      阅读:97      评论:0      收藏:0      [点我收藏+]

标签:需要   n+1   add   std   max   set   pop   uil   string   

题目

下水道的主干路由n个节点和\(n-1\)条边所组成,每条边通过它都需要一个时间\(t_i\)这种边是双向的

下水道上有一些塌陷,我们用\((l_1,r_1,l_2,r_2,c)\)来描述,表示从\(l_1\)\(r_1\)路径上的点,到\(l_2\)\(r_2\)路径上的任意一个点所需要的时间为\(c\)注意塌陷是单向的

求每一个点到目标节点\(k\)的最快时间

思路

\(k\)转换\(k\)到每一个点,塌陷反过来建就好了

之后考虑塌陷

直接树链剖分暴力建图即可

代码

#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#include<cstdio>
using namespace std;
void read(int &x)
{
    x=0;
    int f=1;
    char c=getchar();
    while('0'>c||c>'9')
    {
        if(c=='-')
            f=-1;
        c=getchar();
    }
    while('0'<=c&&c<='9')
    {
        x=(x<<3)+(x<<1)+c-'0';
        c=getchar();
    }
    x*=f;
}
void read(long long &x)
{
    x=0;
    int f=1;
    char c=getchar();
    while('0'>c||c>'9')
    {
        if(c=='-')
            f=-1;
        c=getchar();
    }
    while('0'<=c&&c<='9')
    {
        x=(x<<3)+(x<<1)+c-'0';
        c=getchar();
    }
    x*=f;
}
void write(long long x)
{
    if(x>9)
        write(x/10);
    putchar(x%10+'0');
}
struct node
{
    #define MAXN 250005
    struct node_tre
    {
        int l;
        int r;
    }tre[2][MAXN*4];
    struct node_g
    {
        int e;
        long long w;
        friend bool operator < (const node_g &a,const node_g &b)
        {
            return a.w>b.w;
        }
    };
    int n,m,s;
    int cnt;
    vector<node_g> tree[MAXN];
    vector<node_g> g[9*MAXN+100005*2];
    int id[MAXN];
    int wson[MAXN];
    int siz[MAXN];
    int ori[MAXN];
    int dep[MAXN];
    int top[MAXN];
    int fa[MAXN];
    long long dis[9*MAXN+100005*2];
    bool vis[9*MAXN+100005*2];
    priority_queue<node_g> q;
    #undef MAXN
    void add_edge(int u,int v,long long w)
    {
        tree[u].push_back((node_g){v,w});
    }
    void dfs1(int u,int fa)
    {
        int maxx=-1;
        siz[u]=1;
        dep[u]=dep[fa]+1;
        for(int i=0;i<tree[u].size();i++)
        {
            int v=tree[u][i].e;
            if(v!=fa)
            {
                dfs1(v,u);
                siz[u]+=siz[v];
                if(siz[v]>maxx)
                {
                    maxx=siz[v];
                    wson[u]=v;
                }
            }
        }
    }
    void dfs2(int u,int top_chain)
    {
        top[u]=top_chain;
        id[u]=++cnt;
        ori[cnt]=u;
        if(wson[u])
            dfs2(wson[u],top_chain);
        for(int i=0;i<tree[u].size();i++)
        {
            int v=tree[u][i].e;
            
            if(v!=wson[u]&&dep[v]==dep[u]+1)
            {
                fa[v]=u;
                dfs2(v,v);
            }
                
        }
    }
    void build(int l,int r,int k)
    {
        tre[0][k].l=tre[1][k].l=l;
        tre[0][k].r=tre[1][k].r=r;
        if(l==r)
        {
            g[l].push_back((node_g){n+k,0});
            g[5*n+k].push_back((node_g){l,0});
            return;
        }
        g[n+(k<<1)].push_back((node_g){n+k,0});
        g[n+(k<<1|1)].push_back((node_g){n+k,0});
        g[5*n+k].push_back((node_g){5*n+(k<<1),0});
        g[5*n+k].push_back((node_g){5*n+(k<<1|1),0});
        int mid=(l+r)>>1;
        build(l,mid,k<<1);
        build(mid+1,r,k<<1|1);
    }
    void init()
    {
        dfs1(1,0);
        dfs2(1,1);
        build(1,n,1);
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<tree[i].size();j++)
            {
                int v=tree[i][j].e;
                long long w=tree[i][j].w;
                g[id[i]].push_back((node_g){id[v],w});
                g[id[v]].push_back((node_g){id[i],w});
            }
        }
        cnt=9*n;
    }
    void change_tre(int l,int r,int id,int k,int opt)
    {
        if(l>tre[opt][k].r||tre[opt][k].l>r)
            return;
        if(l<=tre[opt][k].l&&tre[opt][k].r<=r)
        {
            if(opt==0)
                g[n+k].push_back((node_g){id,0});
            else
                g[id].push_back((node_g){5*n+k,0});
            return;
        }
        change_tre(l,r,id,k<<1,opt);
        change_tre(l,r,id,k<<1|1,opt);
    }
    void change(int x,int y,int st,int opt)
    {
        while(top[x]!=top[y])
        {
            if(dep[top[x]]>dep[top[y]])
                swap(x,y);
            change_tre(id[top[y]],id[y],st,1,opt);
            y=fa[top[y]];
        }
        if(dep[x]<dep[y])
            swap(x,y);
        change_tre(id[y],id[x],st,1,opt);
    }
    void link(int l1,int r1,int l2,int r2,long long w)
    {
        change(l1,r1,++cnt,0);
        change(l2,r2,++cnt,1);
        g[cnt-1].push_back((node_g){cnt,w});
    }
    void dij()
    {
        memset(dis,0x3f,sizeof(dis));
        q.push((node_g){id[s],0});
        dis[id[s]]=0;
        while(!q.empty())
        {
            node_g u=q.top();
            q.pop();
            if(vis[u.e])
                continue;
            vis[u.e]=1;
            for(int i=0;i<g[u.e].size();i++)
            {
                int v=g[u.e][i].e;
                long long w=g[u.e][i].w;
                if(dis[u.e]+w<dis[v])
                {
                    dis[v]=w+dis[u.e];
                    q.push((node_g){v,dis[v]});
                }
            }
        }
    }
    void pr()
    {
        for(int i=1;i<=n;i++)
        {
            write(dis[id[i]]);
            putchar('\n');
        }
    }
}tre;
int main()
{
    read(tre.n);
    read(tre.m);
    read(tre.s);
    for(int i=1,u,v;i<tre.n;i++)
    {
        long long w;
        read(u);
        read(v);
        read(w);
        tre.add_edge(u,v,w);
        tre.add_edge(v,u,w);
    }
    tre.init();
    for(int i=1,l1,r1,l2,r2;i<=tre.m;i++)
    {
        long long w;
        read(l1);
        read(r1);
        read(l2);
        read(r2);
        read(w);
        swap(l1,l2);
        swap(r1,r2);
        tre.link(l1,r1,l2,r2,w);
    }
    tre.dij();
    tre.pr();
    return 0;
}

习题:树上的最短路(树链剖分优化建图)

标签:需要   n+1   add   std   max   set   pop   uil   string   

原文地址:https://www.cnblogs.com/loney-s/p/12237607.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!