Description

Solution

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

现在考虑两两连边 , \(lcp\) 就是两个点在 \(trie\) 树上的 \(lca\) 的深度.

这样连边是 \(O(m^2)\) 的 , 考虑优化 , 我们把一个点的出边和入边都单独拿出来 , 并按照 \(dfs\) 序排序 , 设排序之后的数组为 \(q\).

设 \(h[i]=lcp(dep(lca(q[i],q[i+1])))\) , 那么 \(lcp(i,j)=min(h[i],h[i+1]...h[j-1])\) , 这就是后缀数组求 \(lcp\) 时的思想 , 把 \(height\) 数组取 \(min\) .

由于是求最小值 , 我们只需要把所有可能的走法都构造出来 , 然后取 \(min\) 就行了.

于是这么考虑 , 建立两行虚点前缀节点和后缀节点 , 从 \(q[i]\) 走到 \(q[i+1]\) 最多付出 \(h[i]\) 的代价 , \(dfs\) 序相邻的连代价为 \(h[i]\) 的边 , 并且把 \(dfs\) 序上的点都用虚点串起来 , 这样跑最短路的时候就可以取 \(min\) 了.

#include<bits/stdc++.h>
#define I vector<int>::iterator
using namespace std;
template<class T>void gi(T &x){
int f;char c;
for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
}
const int N=1000010,inf=2e9;
vector<int>OT[N],IN[N];
int head[N],nxt[N*2],to[N*2],num=0,q[N],dfn[N],DFN=0;
int pl[N],pr[N],sl[N],sr[N],tt,dis[N*2],v[N];
inline void link(int x,int y,int z){
nxt[++num]=head[x],to[num]=y,head[x]=num,dis[num]=z;}
int n,m,K,d[N],dep[N],fa[N][20];
inline void dfs(int x){
dfn[x]=++DFN;
for(int i=1;i<=18;i++)fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=head[x];i;i=nxt[i]){
int u=to[i];
dep[u]=dep[x]+1,fa[u][0]=x,dfs(u);
}
}
inline int lca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=18;i>=0;i--)if((dep[x]-dep[y])>>i&1)x=fa[x][i];
if(x==y)return x;
for(int i=18;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
inline bool comp(int i,int j){return dfn[d[abs(i)]]<dfn[d[abs(j)]];}
inline void build(int x){
int cnt=0;
for(I it=IN[x].begin();it!=IN[x].end();++it)q[++cnt]=*it;
for(I it=OT[x].begin();it!=OT[x].end();++it)q[++cnt]=-*it;
sort(q+1,q+cnt+1,comp);
for(int i=1;i<=cnt;i++){
pl[i]=++tt,pr[i]=++tt;
sl[i]=++tt,sr[i]=++tt;
if(i>1)link(pl[i-1],pl[i],0),link(pr[i-1],pr[i],0),
link(sl[i],sl[i-1],0),link(sr[i],sr[i-1],0);
if(q[i]>0)link(q[i],pl[i],0),link(q[i],sl[i],0);
else q[i]=-q[i],link(pr[i],q[i],0),link(sr[i],q[i],0);
}
for(int i=1;i<cnt;i++){
int z=dep[lca(d[q[i]],d[q[i+1]])];
link(pl[i],pr[i+1],z),link(sl[i+1],sr[i],z);
}
}
int f[N];bool vis[N];
struct data{int x,v;};
inline bool operator <(data i,data j){return i.v>j.v;}
priority_queue<data>Q;
inline void dj(){
int k=0;
while(!Q.empty()){
int x=Q.top().x;Q.pop();
if(vis[x])continue;
++k,vis[x]=1;
if(k==tt)break;
for(int i=head[x];i;i=nxt[i]){
int u=to[i];
if(!vis[u] && f[x]+dis[i]+v[u]<f[u])
f[u]=f[x]+dis[i]+v[u],Q.push((data){u,f[u]});
}
}
while(!Q.empty())Q.pop();
}
inline void work(){
int x,y,z;
cin>>n>>m>>K;
tt=m,num=DFN=0;
for(int i=0;i<N;i++)f[i]=inf,head[i]=v[i]=d[i]=vis[i]=0;
for(int i=1;i<=n;i++)IN[i].clear(),OT[i].clear();
for(int i=1;i<=m;i++){
gi(x),gi(y),gi(v[i]),gi(d[i]);
if(x==1)Q.push((data){i,v[i]}),f[i]=v[i];
OT[x].push_back(i),IN[y].push_back(i);
}
for(int i=2;i<=K;i++)gi(x),gi(y),gi(z),link(x,y,0);
dfs(1);
memset(head,0,sizeof(head)),num=0;
for(int i=1;i<=n;i++)build(i);
dj();
for(int i=2,ans=f[0];i<=n;i++,ans=f[0]){
for(I it=IN[i].begin();it!=IN[i].end();++it)ans=min(ans,f[*it]);
printf("%d\n",ans);
}
}
int main(){
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
int T;cin>>T;
while(T--)work();
return 0;
}

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

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

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

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

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

  3. [SDOI2017]天才黑客

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

  4. Luogu P3783 [SDOI2017]天才黑客

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

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

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

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

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

  7. BZOJ4912 : [Sdoi2017]天才黑客

    建立新图,原图中每条边在新图中是点,点权为$w_i$,边权为两个字符串的LCP. 对字典树进行DFS,将每个点周围一圈边对应的字符串按DFS序从小到大排序. 根据后缀数组利用height数组求LCP的 ...

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

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

  9. 洛谷P3783 [SDOI2017]天才黑客(前后缀优化建图+虚树+最短路)

    题面 传送门 题解 去看\(shadowice\)巨巨写得前后缀优化建图吧 话说我似乎连线段树优化建图的做法都不会 //minamoto #include<bits/stdc++.h> # ...

随机推荐

  1. Alwayson--与复制的影响

    在主副本上建立复制后,复制的事务日志读取代理(log reader)不会读取尚未同步到辅助副本的日志,因为辅助副本可能在下一时刻转化成为主副本,变为新的复制发布服务器,为此需要保证复制处理的日志总慢于 ...

  2. 简单了解 iTextSharp实现HTML to PDF

    查了下 转PDF的各种框架   发现大部分都是收费的. 发现一款免费的iTextSharp  就想玩一下 只是简单做个HTML 转PDF  没有过深的探究. 首先 我在项目中引入iTextSharp  ...

  3. 《JavaScript高级程序设计》5.5 Function类型

    5.5 Function类型 函数实质上是对象, 每个函数都是Function类型的实例, 并且都和其他引用类型一样具有属性和方法. 因此函数名实际上也是一个指向函数对象的指针, 不会与某个函数绑定. ...

  4. day70 csrf简单用法 &Django ContentType

    一. 什么是跨站请求伪造 CSRF def transfer(request): if request.method =='POST': from_ =request.POST.get('from') ...

  5. jQuery ajax的jsonp跨域请求

    一直在听“跨域跨域”,但是什么是跨域呢?今天做了一些了解.(利用jQuery的jsonp) jQuery使用JSONP跨域 JSONP跨域是利用script脚本允许引用不同域下的js实现的,将回调方法 ...

  6. Android四种数据存储方式

    一.SharedPreference数据存储篇 1.作用范围 (1).它是一种轻型的数据存储方式 (2).本质是基于XML文件存储key-value键值对数据 (3).通常用来存储一些简单的配置方式 ...

  7. Android - Android Studio 3.0去掉方法参数提示

    升级到3.0之后,最明显的一个就是在调用方法的时候多了一个参数提示.有利有弊,看着不是很舒服.就想去掉. 提示样式如下: 去掉提示: 原文地址: https://blog.csdn.net/stude ...

  8. Weekly Contest 132

    1025. Divisor Game Alice and Bob take turns playing a game, with Alice starting first. Initially, th ...

  9. 1.python的一些规范

    Python的一些规范 1.标识符 定义:允许作为名字的有效字符串集合 名字必须有实际意义,可读性好 首字母必须是字母或下划线(_) 剩下的字符可以是字母和数字或者下划线 大小写敏感 两种风格:con ...

  10. 鬼知道是啥系列之——STL(lower_bound(),upper_bound() )

    引子,不明觉厉:   百度,渐入佳境: 头铁,入门到放弃: lower_bound(): 头文件:  #include<algorithm>函数功能:  函数lower_bound()在f ...