zoukankan      html  css  js  c++  java
  • Luogu P3783 [SDOI2017]天才黑客

    题目
    调了差不多有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)=minlimits_{kin[i,j)}l_k)
    那么一种可行的优化建图是利用单调栈求出各个(l_i)被取到的区间,然后线段树优化建图,边数为(O(mlog^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
    ",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;}
    
  • 相关阅读:
    python报错:ERROR: No matching distribution found for dns.resolver
    CVE-2013-4710 WebView addJavascriptInterface远程执行代码
    AndroiBugs Android漏洞扫描器
    如何预测股票分析--线性回归
    如何预测股票分析--移动平均
    Mac升级后如何查看自己的网络端口
    盘它!!一步到位,Tensorflow 2的实战 !!LSTM下的股票预测(附详尽代码及数据集)
    找了好久的塔塔饮料数据集!!!!
    dataset中shuffle()、repeat()、batch()用法
    关于Matplotlib中No module named 'matplotlib.finance'的解决办法
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/11791278.html
Copyright © 2011-2022 走看看