BZOJ 4912: [Sdoi2017]天才黑客 前缀和优化建图最短路

时间:2019-08-24
本文章向大家介绍BZOJ 4912: [Sdoi2017]天才黑客 前缀和优化建图最短路,主要包括BZOJ 4912: [Sdoi2017]天才黑客 前缀和优化建图最短路使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

title

BZOJ 4912

LUOGU 3783

Description

内联网中有 \(n\) 个节点(从 \(1\)\(n\) 标号)和 \(m\) 条单向网线,中央控制系统在第 \(1\) 个节点上,每条网线单向连接内联网中的某两个节点,从 \(1\) 号节点出发经过若干条网线总能到达其他任意一个节点。每个节点都可以运行任意的应用程序,应用程序会携带一条通信口令,当且仅当程序的口令与网线的口令相同时,程序才能通过这条网线到达另一端的节点继续运行,并且通过每条网线都需要花费一定的时间。

每个应用程序可以在任意一个节点修改通信口令,修改通信口令花费的时间可以忽略不计,但是为了减小修改量,需要先调用一个子程序来计算当前程序的口令和网线的口令的最长公共前缀(记其长度为 \(len\) ),由于获取网线的口令的某个字符会比较耗时,调用一次这个子程序需要花费 \(len\) 个单位时间。

除此之外,小Q同学还在中央控制系统中发现了一个字典,每条网线的口令都是字典中的某个字符串。具体来说,这个字典是一棵 \(k\) 个节点(从 \(1\)\(k\) 标号)的有根树,其中根是第 \(1\) 个节点,每条边上有一个字符,字符串 \(S\) 在字典中当且仅当存在某个点 \(u\) 使得从根节点出发往下走到 \(u\) 的这条路径上的字符顺次拼接构成 \(S\)

现在小Q同学在 \(1\) 号节点同时开启了 \(n-1\) 个应用程序,这些应用程序同时运行且互不干扰,每个程序的通信口令都为空,他希望用最短的时间把这些程序分别发送到其他节点上,你需要帮小Q同学分别计算出发送到第 \(i(=2,3,\dots ,n)\) 个节点的程序完成任务的最短时间。

analysis

参考了 dsfr\(blog\)

首先我们把边看成点,把点看成边来建图。每条边拆成两个点连这条边的费用。

对于每一个点,我们在它的所有入边和出边之间两两连边,费用为其 \(lca\) 深度。

这样的话就可以直接跑最短路了。

这样的话显然不能过,考虑优化。

这里有两种做法:

  • 第一种是对于每个点,把和它相邻的每条边的节点拿出来建虚树,然后在 \(dfs\) 序上建线段树来优化连边。

  • 第二种:
    • 假如现在有 \(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]\) 的费用来互相访问。我们只要建立前缀虚点和后缀虚点来优化连边即刻。 点数 \(O(m)\),边数 \(O(m)\),总复杂度 \(O(mlogm)\)

code

#include<bits/stdc++.h>
#define mp std::make_pair
typedef std::pair<int,int> pii;
typedef long long ll;
const int maxn=5e4+10,maxm=maxn*10;
const ll inf=1ll<<60;
typedef int iarr[maxn];

namespace IO
{
    char buf[1<<15],*fs,*ft;
    inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
    template<typename T>inline void read(T &x)
    {
        x=0;
        T f=1, ch=getchar();
        while (!isdigit(ch) && ch^'-') ch=getchar();
        if (ch=='-') f=-1, ch=getchar();
        while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
        x*=f;
    }

    char Out[1<<24],*fe=Out;
    inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
    template<typename T>inline void write(T x,char str)
    {
        if (!x) *fe++=48;
        if (x<0) *fe++='-', x=-x;
        T num=0, ch[20];
        while (x) ch[++num]=x%10+48, x/=10;
        while (num) *fe++=ch[num--];
        *fe++=str;
    }
}

using IO::read;
using IO::write;

template<typename T>inline bool chkMin(T &a,const T &b) { return a>b ? (a=b, true) : false; }
template<typename T>inline bool chkMax(T &a,const T &b) { return a<b ? (a=b, true) : false; }
template<typename T>inline T min(T a,T b) { return a<b ? a : b; }
template<typename T>inline T max(T a,T b) { return a>b ? a : b; }

struct Graph
{
    int ver[maxm<<1],edge[maxm<<1],Next[maxm<<1],head[maxm],len;
    inline void Clear()
    {
        memset(head,0,sizeof(head));
        len=0;
    }

    inline void add(int x,int y,int z)
    {
        ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
    }
}G, A;

iarr id1,id2,pts;
namespace lca
{
    int dfn[maxn],id;
    int dep[maxn],f[maxn][21];
    inline void dfs(int x)
    {
        dfn[x]=++id;
        for (int i=1; i<=20; ++i) f[x][i]=f[f[x][i-1]][i-1];
        for (int i=A.head[x]; i; i=A.Next[i])
        {
            int y=A.ver[i];
            if (y==f[x][0]) continue;
            f[y][0]=x;
            dep[y]=dep[x]+1;
            dfs(y);
        }
    }

    inline int LCA(int x,int y)
    {
        if (dep[x]>dep[y]) std::swap(x,y);
        for (int i=20; i>=0; --i)
            if (dep[y]-(1<<i)>=dep[x]) y=f[y][i];
        if (x==y) return x;
        for (int i=20; i>=0; --i)
            if (f[x][i]^f[y][i]) x=f[x][i],y=f[y][i];
        return f[x][0];
    }

    inline bool cmp(int a,int b)
    {
        return dfn[pts[a]]<dfn[pts[b]];
    }
}

using lca::dfs;
using lca::LCA;
using lca::cmp;

ll dist[maxm];
bool vis[maxm];
int a[maxn],a1,tot;
inline void Dijkstra(int s)
{
    for (int i=0; i<=tot; ++i) dist[i]=inf,vis[i]=0;
    std::priority_queue<pii,std::vector<pii>,std::greater<pii> >q;
    q.push(mp(0,s));dist[s]=0;
    while (!q.empty())
    {
        int x=q.top().second;
        q.pop();
        if (vis[x]) continue;
        vis[x]=1;
        for (int i=G.head[x]; i; i=G.Next[i])
        {
            int y=G.ver[i], z=G.edge[i];
            if (chkMin(dist[y],dist[x]+z)) q.push(mp(dist[y],y));
        }
    }
}

iarr In, InNext, InHead, InPre, InSuf;
iarr Out,OutNext,OutHead,OutPre,OutSuf;
inline void Clear()
{
    memset(InHead,0,sizeof(InHead));
    memset(OutHead,0,sizeof(OutHead));
    G.Clear(), A.Clear();
}

int main()
{
    int T;read(T);
    while (T--)
    {
        Clear();
        int n,m,k;
        read(n);read(m);read(k);
        tot=m<<1;
        for (int i=1,x,y,z; i<=m; ++i)
        {
            read(x),read(y),read(z),read(pts[i]);
            id1[i]=(i<<1)-1,id2[i]=i<<1;
            G.add(id1[i],id2[i],z);
            InNext[i]=InHead[y], InHead[y]=i;
            OutNext[i]=OutHead[x], OutHead[x]=i;
        }
        for (int i=1,x,y,z; i<k; ++i) read(x),read(y),read(z),A.add(x,y,z);
        dfs(1);
        for (int x=1; x<=n; ++x)
        {
            int a1=0;
            for (int i=InHead[x]; i; i=InNext[i]) a[++a1]=i,In[i]=1;
            for (int i=OutHead[x]; i; i=OutNext[i]) a[++a1]=i,Out[i]=1;
            std::sort(a+1,a+a1+1,cmp);
            for (int i=1; i<=a1; ++i)
            {
                InPre[i]=++tot, OutPre[i]=++tot;
                if (In[a[i]]) G.add(id2[a[i]],InPre[i],0);
                if (Out[a[i]]) G.add(OutPre[i],id1[a[i]],0);
                if (i>1) G.add(InPre[i-1],InPre[i],0),G.add(OutPre[i-1],OutPre[i],0);
            }
            for (int i=a1; i>=1; --i)
            {
                InSuf[i]=++tot, OutSuf[i]=++tot;
                if (In[a[i]]) G.add(id2[a[i]],InSuf[i],0);
                if (Out[a[i]]) G.add(OutSuf[i],id1[a[i]],0);
                if (i<a1) G.add(InSuf[i+1],InSuf[i],0),G.add(OutSuf[i+1],OutSuf[i],0);
            }
            for (int i=1; i<a1; ++i)
            {
                int d=lca::dep[LCA(pts[a[i]],pts[a[i+1]])];
                G.add(InPre[i],OutPre[i+1],d);
                G.add(InSuf[i+1],OutSuf[i],d);
            }
            for (int i=1; i<=a1; ++i) In[a[i]]=Out[a[i]]=0;
        }
        for (int i=OutHead[1]; i; i=OutNext[i]) G.add(0,id1[i],0);
        Dijkstra(0);
        for (int x=2; x<=n; ++x)
        {
            ll ans=inf;
            for (int i=InHead[x]; i; i=InNext[i]) ans=min(ans,dist[id2[i]]);
            write(ans,'\n');
        }
    }
    IO::flush();
    return 0;
}

原文地址:https://www.cnblogs.com/G-hsm/p/11405825.html