ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Luogu P3783 [SDOI2017]天才黑客

2019-11-04 11:54:43  阅读:336  来源: 互联网

标签:le int Luogu P3783 fa 入点 出点 SDOI2017 define


题目
调了差不多有10h吧,真的我太难了。
首先一个比较自然的想法是化边为点,每条边拆成一个入点和一个出点,入点到出点连一条长度为这条边的边权的边。同时对于两条边而言,从各自的出点到对方的入点连一条长度为两条边的字符串的\(lcp\)的边。
这样建出来的边数是\(O(m^2)\)的,非常的不优秀。
我们可以发现一件事情:我们把所有字符串按其在trie上的dfs序排个序,设\(l_i=lcp(s_i,s_{i+1})=dep_{lca(s_i,s_j)}\),那么\(lcp(s_i,s_j)=\min\limits_{k\in[i,j)}l_k\)。
那么一种可行的优化建图是利用单调栈求出各个\(l_i\)被取到的区间,然后线段树优化建图,边数为\(O(m\log^2m)\)。
但是我们有更加优秀的优化建图的方法。
每个\(l_i\)代表\(\le i\)的出点可以通过\(l_i\)的代价走到\(>i\)的入点,\(>i\)的出点可以通过\(l_i\)的的代价走到\(\le i\)的入点。
直接连就是\(O(n^3)\)的了。
我们可以这样连:
\(i\)的入点和出点分别与\(i+1\)的入点和出点连一条\(0\)的边。
对于\(\le i\)的出点可以通过\(l_i\)的代价走到\(>i\)的入点,连\(i\)的出点到\(i+1\)的入点边权为\(l_i\)的边。
对于\(>i\)的出点可以通过\(l_i\)的的代价走到\(\le i\)的入点这种边,我们可以把\(i\)的入点和出点都拆成两个,一对处理上面那种,另一对处理下面这种。
所以另一对就这么连:
\(i\)的入点和出点分别与\(i-1\)的入点和出点连一条\(0\)的边。
对于\(>i\)的出点可以通过\(l_i\)的代价走到\(\le i\)的入点,连\(i+1\)的出点到\(i\)的入点边权为\(l_i\)的边。
那么每条边的两个入点到两个出点都要连长度为这条边边权的边。
最后建一个超级原点,到所有从\(1\)出发的边的入点连一条长度为\(0\)的边,跑一遍最短路。
对于每一个点在原图中的最短路,就是所有原图中指向它的点的出点的最短路。
码风比较清奇?凑合着看吧。

#include<bits/stdc++.h>
#define ll long long
#define pi pair<int,int>
#define Pi pair<ll,int>
#define pb push_back
#define fi first
#define se second
using namespace std;
int read()
{int x=0,c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))x=x*10+c-48,c=getchar();return x;}
void swap(int &a,int &b)
{a^=b^=a^=b;}
const int N=20007;
int n,m,k,dfn[N],dep[N];
namespace trie
{
    int fa[N][18],T;vector<int>E[N];
    void clear()
    {for(int i=1;i<=k;++i)E[i].clear();memset(fa,0,sizeof fa),T=0;}
    void add(int w,int v,int u)
    {E[u].pb(v);}
    void dfs(int u)
    {for(int i=0;fa[u][i];++i)fa[u][i+1]=fa[fa[u][i]][i];dfn[u]=++T;for(int v:E[u])if(v^fa[u][0])dep[v]=dep[u]+1,fa[v][0]=u,dfs(v);}
    int lca(int u,int v)
    {if(dep[u]<dep[v])swap(u,v);for(int d=dep[u]-dep[v],i=0;d;d>>=1,++i)if(d&1)u=fa[u][i];if(u==v)return u;for(int i=17;~i;--i)if(fa[u][i]^fa[v][i])u=fa[u][i],v=fa[v][i];return fa[u][0];}
    void build()
    {dfs(1);}
}
namespace graph
{
    const int M=50007,V=M*4;
    int t,s,p[V],vis[V];ll dis[V];vector<pi>e[V];vector<int>a[M],b[M],c[M],d[M],vec;priority_queue<Pi>q;
    int cmp(int i,int j)
    {return dfn[p[i]]<dfn[p[j]];}
    void clear()
    {for(int i=1;i<=s+1;++i)e[i].clear(),a[i].clear(),b[i].clear(),c[i].clear(),d[i].clear();t=0;}
    void add(int u,int v,int w)
    {e[u].pb(pi(v,w));}
    void ins(int pos,int w,int v,int u)
    {
    if(u==1)add(s,t+1,0),add(s,t+3,0);for(int i=1;i<=4;i++)p[t+i]=pos; 
        add(t+1,t+2,w),add(t+1,t+4,w),add(t+3,t+4,w),add(t+3,t+2,w),a[u].pb(++t),b[v].pb(++t),c[u].pb(++t),d[v].pb(++t);
    }
    void build()
    {
    for(int i,j,k,u=1,w;u<=n;++u)
    {
        sort(a[u].begin(),a[u].end(),cmp),sort(b[u].begin(),b[u].end(),cmp),sort(c[u].begin(),c[u].end(),cmp),sort(d[u].begin(),d[u].end(),cmp);
        for(i=0;i+1<a[u].size();++i)add(a[u][i],a[u][i+1],0);
        for(i=0;i+1<b[u].size();++i)add(b[u][i],b[u][i+1],0);
        for(i=0;i+1<c[u].size();++i)add(c[u][i+1],c[u][i],0);
        for(i=0;i+1<d[u].size();++i)add(d[u][i+1],d[u][i],0);
        vec.resize(a[u].size()+b[u].size()),merge(b[u].begin(),b[u].end(),a[u].begin(),a[u].end(),vec.begin(),cmp);
        for(k=i=j=0;k+1<vec.size();++k)
        {
        (vec[k]&1?++j:++i),w=dep[trie::lca(p[vec[k]],p[vec[k+1]])];
        if(i&&j!=a[u].size()) add(b[u][i-1],a[u][j],w);
        if(i!=d[u].size()&&j) add(d[u][i],c[u][j-1],w);
        }
    }
    }
    void dij()
    {
    memset(dis,0x3f,sizeof dis),memset(vis,0,sizeof vis),q.push(Pi(dis[s]=0,s));
    for(int u;!q.empty();)
    {
        u=q.top().se,q.pop();if(vis[u])continue;vis[u]=1;
        for(auto[v,w]:e[u]) if(dis[v]>dis[u]+w)dis[v]=dis[u]+w,q.push(Pi(-dis[v],v));
    }
    }
    void solve()
    {for(int i=2;i<=n;++i){ll ans=1e18;for(int x:b[i])ans=min(ans,dis[x]);for(int x:d[i])ans=min(ans,dis[x]);printf("%lld\n",ans);}}
}
void solve()
{
    n=read(),m=read(),k=read(),graph::s=4*m+1,trie::clear(),graph::clear();
    for(int i=1;i<=m;++i)graph::ins(read(),read(),read(),read());
    for(int i=2;i<=k;++i)trie::add(read(),read(),read());
    trie::build(),graph::build(),graph::dij(),graph::solve();
}
int main()
{for(int T=read();T;--T)solve();return 0;}

标签:le,int,Luogu,P3783,fa,入点,出点,SDOI2017,define
来源: https://www.cnblogs.com/cjoierShiina-Mashiro/p/11791278.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有