博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[SDOI2017]天才黑客
阅读量:6811 次
发布时间:2019-06-26

本文共 3129 字,大约阅读时间需要 10 分钟。

题目大意

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

题解

一看肯定是一个最短路问题,现在的关键问题是如何把这张图建出来。

我们可以枚举每个点作为两条边的中转点,然后直接把每条边看作一个点,对应的去连边复杂度肯定不对。

我们发现对于所有点,和它们相连的所有边的总和是\(O(m)\)的,所以我们考虑对每个点,对它相邻的所有边建一个虚树。

然后观察到两条边代表的字符串的最长公共前缀也是它们在字典树上的\(LCA\),所以我们在虚树上枚举\(LCA\),然后再去枚举进来的边,那么可以作为连出去的边在虚树上的\(dfs\)序是一段或两段连续的区间,然后再对\(dfs​\)序建线段树优化一下连边就可以了。

代码

写了大半天,自闭了。。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#define mm make_pair#define P pair
#define N 100009#define ls tr[cnt].l#define rs tr[cnt].rusing namespace std;typedef long long ll;priority_queue
>q;int dfn[N],head[N*30],deep[N],p[20][N],tot,a[N],st[N],top,rbs[N],rot,num,_tag[N],tott,df[N],ddf,size[N],rt1,rt2,n,m,k;ll dis[N*30];bool vis[N*30];vector
vec[N],ed[N],ru[N],chu[N],co1[N],co2[N];vector
::iterator it;inline ll rd(){ ll x=0;char c=getchar();bool f=0; while(!isdigit(c)){if(c=='-')f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?-x:x;}inline bool cmp(int a,int b){return dfn[a]
dis[u]+e[i].l+x){ dis[v]=dis[u]+e[i].l+x; q.push(mm(-dis[v],v)); } } }}void dfs(int u){ dfn[u]=++dfn[0]; for(int i=1;(1<
<=deep[u];++i)p[i][u]=p[i-1][p[i-1][u]]; for(vector
::iterator it=vec[u].begin();it!=vec[u].end();++it){ int v=*it;deep[v]=deep[u]+1;p[0][v]=u; dfs(v); }}inline int getlca(int u,int v){ if(deep[u]
=0;--i)if(deep[u]-(1<
=deep[v])u=p[i][u]; if(u==v)return u; for(int i=19;i>=0;--i)if(p[i][u]!=p[i][v])u=p[i][u],v=p[i][v]; return p[0][u];}inline void get_tree(){ sort(a+1,a+num+1); num=unique(a+1,a+num+1)-a-1; sort(a+1,a+num+1,cmp); st[top=1]=a[1];rbs[rbs[0]=1]=a[1];rot=a[1]; for(int i=2;i<=num;++i){ if(st[top]==a[i])continue; int x=a[i],lca=getlca(a[i],st[top]); if(lca==st[top]){st[++top]=a[i];rbs[++rbs[0]]=a[i];continue;} while(top>1){ int x=st[top],y=st[top-1];top--; if(dfn[lca]>=dfn[y]){ link(lca,x);break; } link(y,x); } if(dfn[lca]
1){link(st[top-1],st[top]);top--;}}int build(int l,int r,int tag){ int cnt=++tott;tr[cnt].l=tr[cnt].r=0; if(l==r){ int x=_tag[l]; if(!tag){ for(vector
::iterator it=co1[x].begin();it!=co1[x].end();++it)link2(*it,cnt,0); } if(tag){ for(vector
::iterator it=co2[x].begin();it!=co2[x].end();++it)link2(cnt,*it,0); } return cnt; } int mid=(l+r)>>1; ls=build(l,mid,tag);rs=build(mid+1,r,tag); if(!tag)link2(ls,cnt,0),link2(rs,cnt,0); else link2(cnt,ls,0),link2(cnt,rs,0); return cnt;}void upd(int cnt,int l,int r,int L,int R,int tag,int x,int len){ if(l>=L&&r<=R){ if(!tag)link2(cnt,x,len); else link2(x,cnt,len); return; } int mid=(l+r)>>1; if(mid>=L)upd(ls,l,mid,L,R,tag,x,len); if(mid
::iterator it=ed[u].begin();it!=ed[u].end();++it){ int v=*it; dfs2(v); size[u]+=size[v]; }}void dfs3(int u){ int nw=df[u],en=df[u]+size[u]-1,sz=0; int x=++tott; upd(rt1,1,ddf,nw,nw,0,x,0); upd(rt2,1,ddf,nw,en,1,x,deep[u]); for(vector
::iterator it=ed[u].begin();it!=ed[u].end();++it){ int v=*it; dfs3(v);x=++tott; int L=nw+sz+1,R=nw+sz+size[v]; upd(rt1,1,ddf,L,R,0,x,0); if(L>nw)upd(rt2,1,ddf,nw,L-1,1,x,deep[u]); if(R

转载于:https://www.cnblogs.com/ZH-comld/p/10677592.html

你可能感兴趣的文章
NDK图形函数在某些机型下显示花屏的问题
查看>>
Dojo学习笔记(十三):Dojo表单控件——TextBox及其变体
查看>>
一文搞懂HMM(隐马尔可夫模型)
查看>>
使用python和批处理bat脚本ping检测主机连通性
查看>>
MaxScale Binlog Server
查看>>
Python3下OpenCV的安装
查看>>
Qpid第四课 异常以及崩溃
查看>>
C# 调用C++接口
查看>>
【系列4】使用Dockerfile创建带tomcat的Centos Docker镜像
查看>>
webservice返回子类
查看>>
MySQL数据管理1
查看>>
kernel对于SO_REUSEADDR的处理——避免滥用引发Bug
查看>>
Saltstack SLS文件解读
查看>>
LiveUSB像光驱LiveCD一样启动
查看>>
Linux利用sendmail和fetion发送报警通知
查看>>
C/C++中一次性执行多个DOS命令
查看>>
(转载)经典SQL语句大全3-技巧篇
查看>>
在SSIS包中使用 Checkpoint从失败处重新启动包
查看>>
关于项目自动化测试架构的改良计划 - 解析XInclude标记
查看>>
Powershell DSC 5.0 - Push 模式
查看>>