建立新图,原图中每条边在新图中是点,点权为$w_i$,边权为两个字符串的LCP。

对字典树进行DFS,将每个点周围一圈边对应的字符串按DFS序从小到大排序。

根据后缀数组利用height数组求LCP的原理,类似地可以得到:

令$h_i=LCP(str_i,str_{i+1})$,则$LCP(str_l,str_r)=\min(h_{l..r-1})$。

枚举每个$h_i$作为分界线,那么新图中两侧的点均可以通过不超过$h_i$的代价互相访问。

建立一排前缀虚点和后缀虚点然后对应前后缀之间连边即可。

如此建图的点数和边数均为$O(m)$,时间复杂度$O(m\log m)$。

#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
typedef pair<int,int>P;
const int N=50010,inf=~0U>>1;
int Case,n,m,K,i,j,x,y,z,g[N],nxt[N],size[N],f[N],d[N],son[N],loc[N],top[N],dfn;
int gi[N],go[N],V[N<<1],NXT[N<<1],ED;
int cnt,pi[N<<1],po[N<<1],si[N<<1],so[N<<1],cq,q[N<<1];
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
struct E{int a,b,c,d;}e[N];
namespace G{
const int N=450010,M=800010;
int g[N],v[M],w[M],nxt[M],ed,val[N],d[N];priority_queue<P,vector<P>,greater<P> >q;
inline void add(int x,int y,int z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;}
inline void ext(int x,int y){
y+=val[x];
if(y<d[x])q.push(P(d[x]=y,x));
}
void solve(){
for(i=1;i<=cnt;i++)d[i]=inf;
for(i=1;i<=m;i++)if(e[i].a==1)ext(i,0);
while(!q.empty()){
P t=q.top();q.pop();
if(d[t.second]>t.first)continue;
for(i=g[t.second];i;i=nxt[i])ext(v[i],t.first+w[i]);
}
}
}
inline bool cmp(int x,int y){return loc[e[abs(x)].d]<loc[e[abs(y)].d];}
inline void add(int x,int y){nxt[y]=g[x];g[x]=y;}
inline void ADD(int&x,int y){V[++ED]=y;NXT[ED]=x;x=ED;}
void dfs(int x){
size[x]=1;
for(int i=g[x];i;i=nxt[i]){
f[i]=x,d[i]=d[x]+1;
dfs(i),size[x]+=size[i];
if(size[i]>size[son[x]])son[x]=i;
}
}
void dfs2(int x,int y){
loc[x]=++dfn;top[x]=y;
if(son[x])dfs2(son[x],y);
for(int i=g[x];i;i=nxt[i])if(i!=son[x])dfs2(i,i);
}
inline int lca(int x,int y){
for(;top[x]!=top[y];x=f[top[x]])if(d[top[x]]<d[top[y]])swap(x,y);
return min(d[x],d[y]);
}
inline void solve(int x){
int i;
if(!gi[x]||!go[x])return;
cq=0;
for(i=gi[x];i;i=NXT[i])q[++cq]=V[i];
for(i=go[x];i;i=NXT[i])q[++cq]=-V[i];
sort(q+1,q+cq+1,cmp);
for(i=1;i<=cq;i++){
pi[i]=++cnt;
si[i]=++cnt;
po[i]=++cnt;
so[i]=++cnt;
if(i>1){
G::add(pi[i-1],pi[i],0);
G::add(po[i-1],po[i],0);
G::add(si[i],si[i-1],0);
G::add(so[i],so[i-1],0);
}
if(q[i]>0)G::add(q[i],pi[i],0),G::add(q[i],si[i],0);
else q[i]*=-1,G::add(po[i],q[i],0),G::add(so[i],q[i],0);
}
for(i=1;i<cq;i++){
int t=lca(e[q[i]].d,e[q[i+1]].d);
G::add(pi[i],po[i+1],t);
G::add(si[i+1],so[i],t);
}
}
int main(){
read(Case);
while(Case--){
read(n),read(m),read(K);
for(i=1;i<=m;i++){
read(e[i].a),read(e[i].b),read(e[i].c),read(e[i].d);
ADD(gi[e[i].b],i),ADD(go[e[i].a],i);
G::val[i]=e[i].c;
}
cnt=m;
for(i=1;i<K;i++)read(x),read(y),read(z),add(x,y);
dfs(1),dfs2(1,1);
for(i=1;i<=n;i++)solve(i);
G::solve();
for(i=2;i<=n;i++){
x=inf;
for(j=gi[i];j;j=NXT[j])x=min(x,G::d[V[j]]);
printf("%d\n",x);
}
for(i=1;i<=cnt;i++)G::g[i]=G::val[i]=0;
for(i=1;i<=K;i++)g[i]=size[i]=f[i]=d[i]=son[i]=0;
for(i=1;i<=n;i++)gi[i]=go[i]=0;
ED=dfn=G::ed=0;
}
return 0;
}

  

BZOJ4912 : [Sdoi2017]天才黑客的更多相关文章

  1. [LOJ#2270][BZOJ4912][SDOI2017]天才黑客

    [LOJ#2270][BZOJ4912][SDOI2017]天才黑客 试题描述 SD0062 号选手小 Q 同学为了偷到 SDOI7012 的试题,利用高超的黑客技术潜入了 SDOI 出题组的内联网的 ...

  2. BZOJ4912 SDOI2017天才黑客(最短路+虚树)

    容易想到把边当成点重建图跑最短路.将每条边拆成入边和出边,作为新图中的两个点,由出边向入边连边权为原费用的边.对于原图中的每个点,考虑由其入边向出边连边.直接暴力两两连边当然会被卡掉,注意到其边权是t ...

  3. BZOJ4912 [Sdoi2017]天才黑客 【虚树 + 最短路】

    题目链接 BZOJ4912 题解 转移的代价是存在于边和边之间的 所以把边看做点,跑最短路 但是这样做需要把同一个点的所有入边和所有出边之间连边 \(O(m^2)\)的连边无法接受 需要优化建图 膜一 ...

  4. 【BZOJ4912】天才黑客(最短路,虚树)

    [BZOJ4912]天才黑客(最短路,虚树) 题面 BZOJ 洛谷 题解 \(Anson\)爷讲过的题目,然而我还是不会做 只有照着\(zsy\)的程序打我才会做....果然太弱了. 这道题目显然是把 ...

  5. 【LG3783】[SDOI2017]天才黑客

    [LG3783][SDOI2017]天才黑客 题面 洛谷 题解 首先我们有一个非常显然的\(O(m^2)\)算法,就是将每条边看成点, 然后将每个点的所有入边和出边暴力连边跑最短路,我们想办法优化这里 ...

  6. [SDOI2017]天才黑客

    题目大意 给一张有向图,再给一颗字典树,有向图上的每条边有一个非负边权还有一个字典树上的字符串,从一条边到另一条边的代价是那条边的边权和这两个字符串的最长公共前缀,问从1到其他点的最短路. 题解 一看 ...

  7. Luogu P3783 [SDOI2017]天才黑客

    题目大意 一道码量直逼猪国杀的图论+数据结构题.我猪国杀也就一百来行 首先我们要看懂鬼畜的题意,发现其实就是在一个带权有向图上,每条边有一个字符串信息.让你找一个点出发到其它点的最短路径.听起来很简单 ...

  8. [SDOI2017]天才黑客[最短路、前缀优化建图]

    题意 一个 \(n\) 点 \(m\) 边的有向图,还有一棵 \(k\) 个节点的 trie ,每条边上有一个字符串,可以用 trie 的根到某个节点的路径来表示.每经过一条边,当前携带的字符串就会变 ...

  9. bzoj 4912: [Sdoi2017]天才黑客

    Description Solution 这个题和点没什么关系 , 之和边与边之间关系有关 , 我们就把边看作点 , 边权就是 \(lcp\) , 点权看作这条边本来的权值. 现在考虑两两连边 , \ ...

随机推荐

  1. 任务超时退出的方法 C#

    超出时间方法退出.防止卡住. 方法: private static bool ImportTaskTimeout(Action method, int hours) { try { var task ...

  2. Java charAt() 方法

    charAt() 方法用于返回指定索引处的字符.索引范围为从 0 到 length() - 1. 参数 index -- 字符的索引. 返回值 返回指定索引处的字符. 实例 public class ...

  3. python---实现多个有序列表的合并

    我觉得不用抄书上的代码. 遇到实现问题,应该结合python本身的功能去解决. 比如,当合并有序列表时,为什么一定要一项一项比较,而不是使用list的sort函数呢? # coding = utf-8 ...

  4. (Access denied for user 'root'@'slaver1' (using password: YES))

    1.问题描述,启动azkaban的时候报如下所示的错误.之前使用azkaban是root用户,今天使用hadoop用户进行配置和使用,报这个错,说是root连接mysql拒绝了. [hadoop@sl ...

  5. cuda by example【读书笔记1】

    cuda 1. 以前用OpenGL和DirectX API简介操作GPU,必须了解图形学的知识,直接操作GPU要考虑并发,原子操作等等,cuda架构为此专门设计.满足浮点运算,用裁剪后的指令集执行通用 ...

  6. 【译】写好JavaScript条件语句的5个技巧

    译文 当我们写JavaScript代码时,经常会用到到条件判断处理,这里有5个技巧能使你写出更好.更简洁的条件语句. 1.使用Array.includes处理多种条件 让我们来看一下的例子: // c ...

  7. C# 之 日常问题积累(一)

    1.响应在此上下文中不可用(Response). 异常:响应在此上下文中不可用 产生异常的过程:在asp.net程序中添加了一个 类.cs ,其中有一段代码如下 : Response.ClearCon ...

  8. 如何配置使用HTML在线编辑工具

    如何配置使用HTML在线编辑工具 为了更好的.统一的编写统一简单易用的博客,决定采用TinyMCE工具.首先下载TinyMCE4.0包.文件目录如下: 其中, Plugins是插件目录,包括各种插件 ...

  9. js中时间大小的比较

    今天在前台做到一个需要比较两个日期大小的地方,乍一看,发现一个比较奇怪地地方: var t1 = new Date(2018,1,1), t2 = new Date(2018,1,1); consol ...

  10. java大数相加

    import java.math.BigInteger; import java.util.Scanner; public class Bignum{    public static void ma ...