【SDOI2017】天才黑客
【SDOI2017】天才黑客
这题太神了。
先模Claris 大神的题解。
首先我们要将边转换为点。如果暴力连边就会有\(m^2\)的边,于是我们考虑优化建图。
难点在于快速得到两个边的串的\(lcp\),也就是\(trie\)树上的\(lca\)。我们将一堆点按\(dfs\)序排序,然后\(a\)到\(b\)的\(lca\)就是排序后\(min\{lca(a,a+1),lca(a+1,a+2)...lca(b-1,b)\}\),这里的\(min\)是深度最小。
对于原图上的点\(i\),我们就将所有的边按\(dfs\)序拍好序,再复制一倍的虚点,相邻的实点和虚点连权值为\(0\)的边。每个实点向下一个点对应的虚点连权值为\(dep_{lca}\)的边。
然后还要反方向建相同的边,不过不能建在一张图上。
这道题中关于处理一堆点两两之间\(lca\)的方法值得掌握。
代码:
#include<bits/stdc++.h>
#define ll long long
#define N 400005
using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
int n,m,k;
int tot,TOT;
int w[N],t[N];
ll dis[N];
ll ans[N];
vector<int>st[N];
vector<int>e[N];
struct road {
int to,next;
ll c;
}s[N*15];
int h[N],cnt;
void add(int i,int j,int c) {s[++cnt]=(road) {j,h[i],c};h[i]=cnt;}
int id,dfn[N];
void Init() {
cnt=0;
id=0;
memset(h,0,sizeof(h));
memset(t,0,sizeof(t));
memset(w,0,sizeof(w));
memset(dis,0x3f,sizeof(dis));
for(int i=1;i<=k;i++) e[i].clear();
for(int i=1;i<=n;i++) st[i].clear();
}
int dep[N];
int fa[N][20];
bool cmp(int a,int b) {return dfn[t[a]]<dfn[t[b]];}
bool cmp2(int a,int b) {return dfn[t[a]]>dfn[t[b]];}
int lca(int a,int b) {
if(dep[a]<dep[b]) swap(a,b);
for(int i=16;i>=0;i--)
if(fa[a][i]&&dep[fa[a][i]]>=dep[b])
a=fa[a][i];
if(a==b) return a;
for(int i=16;i>=0;i--)
if(fa[a][i]!=fa[b][i])
a=fa[a][i],b=fa[b][i];
return fa[a][0];
}
void dfs(int v) {
dfn[v]=++id;
for(int i=1;i<=16;i++) fa[v][i]=fa[fa[v][i-1]][i-1];
for(int i=0;i<e[v].size();i++) {
int to=e[v][i];
dep[to]=dep[v]+1;
fa[to][0]=v;
dfs(to);
}
}
void build() {
for(int i=1;i<=n;i++) {
sort(st[i].begin(),st[i].end(),cmp);
for(int j=0;j<st[i].size()-1;j++) {
add(st[i][j],st[i][j+1],0);
add(st[i][j]+tot,st[i][j+1]+tot,0);
add(st[i][j],st[i][j+1]+tot,dep[lca(t[st[i][j]],t[st[i][j+1]])]);
}
reverse(st[i].begin(),st[i].end());
for(int j=0;j<st[i].size()-1;j++) {
add(st[i][j]+TOT,st[i][j+1]+TOT,0);
add(st[i][j]+tot+TOT,st[i][j+1]+tot+TOT,0);
add(st[i][j]+TOT,st[i][j+1]+tot+TOT,dep[lca(t[st[i][j]],t[st[i][j+1]])]);
}
}
}
struct node {
int v,d;
node() {v=0,d=0;}
node(int a,int b) {v=a,d=b;}
bool operator <(const node &a)const {return d>a.d;}
};
priority_queue<node>q;
bool vis[N];
void dij() {
memset(vis,0,sizeof(vis));
while(!q.empty()) {
node tem=q.top();q.pop();
int v=tem.v;
if(vis[v]) continue ;
vis[v]=1;
for(int i=h[v];i;i=s[i].next) {
int to=s[i].to;
if(vis[to]) continue ;
if(dis[to]>dis[v]+s[i].c) {
dis[to]=dis[v]+s[i].c;
q.push(node(to,dis[to]));
}
}
}
}
int main() {
int T=Get();
while(T--) {
n=Get(),m=Get(),k=Get();
Init();
tot=m<<1,TOT=tot<<1;
int a,b,c,d;
for(int i=1;i<=m;i++) {
a=Get(),b=Get(),c=Get(),d=Get();
t[i]=t[i+m]=d;
w[i]=w[i+TOT]=c;
st[b].push_back(i);
st[a].push_back(i+m);
add(i+m+tot,i,w[i]);
add(i+m+tot+TOT,i,w[i]);
add(i+m+tot,i+TOT,w[i]);
add(i+m+tot+TOT,i+TOT,w[i]);
}
for(int i=1;i<k;i++) {
a=Get(),b=Get(),c=Get();
e[a].push_back(b);
}
dfs(1);
build();
for(int i=0;i<st[1].size();i++) {
if(st[1][i]>m) {
dis[st[1][i]-m]=dis[st[1][i]-m+TOT]=w[st[1][i]-m];
q.push(node(st[1][i]-m,w[st[1][i]-m]));
q.push(node(st[1][i]-m+TOT,w[st[1][i]-m]));
}
}
dij();
memset(ans,0x3f,sizeof(ans));
for(int i=1;i<=n;i++) {
for(int j=0;j<st[i].size();j++)
if(st[i][j]<=m) {
ans[i]=min(ans[i],min(dis[st[i][j]],dis[st[i][j]+TOT]));
}
}
for(int i=2;i<=n;i++) cout<<ans[i]<<"\n";
}
return 0;
}
【SDOI2017】天才黑客的更多相关文章
- [LOJ#2270][BZOJ4912][SDOI2017]天才黑客
[LOJ#2270][BZOJ4912][SDOI2017]天才黑客 试题描述 SD0062 号选手小 Q 同学为了偷到 SDOI7012 的试题,利用高超的黑客技术潜入了 SDOI 出题组的内联网的 ...
- 【LG3783】[SDOI2017]天才黑客
[LG3783][SDOI2017]天才黑客 题面 洛谷 题解 首先我们有一个非常显然的\(O(m^2)\)算法,就是将每条边看成点, 然后将每个点的所有入边和出边暴力连边跑最短路,我们想办法优化这里 ...
- [SDOI2017]天才黑客
题目大意 给一张有向图,再给一颗字典树,有向图上的每条边有一个非负边权还有一个字典树上的字符串,从一条边到另一条边的代价是那条边的边权和这两个字符串的最长公共前缀,问从1到其他点的最短路. 题解 一看 ...
- Luogu P3783 [SDOI2017]天才黑客
题目大意 一道码量直逼猪国杀的图论+数据结构题.我猪国杀也就一百来行 首先我们要看懂鬼畜的题意,发现其实就是在一个带权有向图上,每条边有一个字符串信息.让你找一个点出发到其它点的最短路径.听起来很简单 ...
- [SDOI2017]天才黑客[最短路、前缀优化建图]
题意 一个 \(n\) 点 \(m\) 边的有向图,还有一棵 \(k\) 个节点的 trie ,每条边上有一个字符串,可以用 trie 的根到某个节点的路径来表示.每经过一条边,当前携带的字符串就会变 ...
- BZOJ4912 SDOI2017天才黑客(最短路+虚树)
容易想到把边当成点重建图跑最短路.将每条边拆成入边和出边,作为新图中的两个点,由出边向入边连边权为原费用的边.对于原图中的每个点,考虑由其入边向出边连边.直接暴力两两连边当然会被卡掉,注意到其边权是t ...
- BZOJ4912 : [Sdoi2017]天才黑客
建立新图,原图中每条边在新图中是点,点权为$w_i$,边权为两个字符串的LCP. 对字典树进行DFS,将每个点周围一圈边对应的字符串按DFS序从小到大排序. 根据后缀数组利用height数组求LCP的 ...
- BZOJ4912 [Sdoi2017]天才黑客 【虚树 + 最短路】
题目链接 BZOJ4912 题解 转移的代价是存在于边和边之间的 所以把边看做点,跑最短路 但是这样做需要把同一个点的所有入边和所有出边之间连边 \(O(m^2)\)的连边无法接受 需要优化建图 膜一 ...
- bzoj 4912: [Sdoi2017]天才黑客
Description Solution 这个题和点没什么关系 , 之和边与边之间关系有关 , 我们就把边看作点 , 边权就是 \(lcp\) , 点权看作这条边本来的权值. 现在考虑两两连边 , \ ...
- 洛谷P3783 [SDOI2017]天才黑客(前后缀优化建图+虚树+最短路)
题面 传送门 题解 去看\(shadowice\)巨巨写得前后缀优化建图吧 话说我似乎连线段树优化建图的做法都不会 //minamoto #include<bits/stdc++.h> # ...
随机推荐
- input type=file 上传文件样式美化(转载)
input type=file 上传文件样式美化 来源:https://www.jianshu.com/p/6390595e5a36 在做input文本上传时,由于html原生的上传按钮比较丑,需要对 ...
- [android] 安卓进程优先级&为什么使用服务
应用程序:一组组件(activity service provider receiver)的集合 一般情况下,一个应用程序对应一个进程 一般情况下,关闭掉应用,关闭掉所有界面,应用程序的进程还在后台运 ...
- 深入浅出LSTM神经网络
转自:https://www.csdn.net/article/2015-06-05/2824880 LSTM递归神经网络RNN长短期记忆 摘要:根据深度学习三大牛的介绍,LSTM网络已被证明比传 ...
- <自动化测试方案书>方案书目录排版
自动化测试方案书 一.介绍 QQ交流群:585499566 这篇是一个系列,用来给需要做自动化测试方案的人做个参考,文章的内容是我收集网上和自己工作经验所得,希望能够给你们有所帮助 背景:因为工作需要 ...
- leetcode-69.x的平方根
leetcode-69.x的平方根 Points 二分查找 牛顿迭代 题意 实现 int sqrt(int x) 函数. 计算并返回 x 的平方根,其中 x 是非负整数. 由于返回类型是整数,结果只保 ...
- js的深层克隆和浅层克隆代码和理解
<script> //判断是不是原始值 //判断是数组还是对象 //建立相应的数组或对象 var obj={ name:'辣鸡', sex:'male', card:['laobi','f ...
- mysql之代码执行结构
本文内容: 什么是代码执行结构 顺序结构 分支结构 循环结构 首发日期:2018-04-18 什么是代码执行结构: 这里所说的代码执行结构就是多条sql语句的执行顺序. 代码执行结构主要用于触发器.存 ...
- 使用Visual Studio Team Services进行压力和性能测试(一)——创建基础的URL压力测试
使用Visual Studio Team Services进行压力和性能测试(一)--创建基础的URL压力测试 概述 压力测试使应用程序更加健壮,并审核在用户负载下的行为,这样我们可以在当前的基础设施 ...
- katalon之web文件上传
参考:https://docs.katalon.com/katalon-studio/docs/webui-upload-file.html#example- 适用范围:tag=input, type ...
- Cas 服务器 Service(Cas客户端)注册信息维护
作为Cas服务器,允许哪些客户端接入与否是通过配置来定义的.对Cas服务器来说,每一个接入的客户端与一个Service配置对应:在Cas服务器启动时加载并注册上这些Service,与之对应的客户端才能 ...