容易想到把边当成点重建图跑最短路。将每条边拆成入边和出边,作为新图中的两个点,由出边向入边连边权为原费用的边。对于原图中的每个点,考虑由其入边向出边连边。直接暴力两两连边当然会被卡掉,注意到其边权是trie上lca的深度,由lca转rmq的做法可知,两点lca即为欧拉序区间中它们之间深度最小的点,于是跑出欧拉序后对入边出边的前后缀建虚点连边即可。当然每次连边时都需要将trie上有用的点提取出来,建虚树即可。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define N 50010
#define inf 2000000000
#define in(i) (i*2+n)
#define out(i) (i*2+n-1)
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{int x=0,f=1;char c=getchar();while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();return x*f;
}
int T,n,m,k,p[N],t;
struct data{int to,nxt,len,s;
}edge[N];
vector<int> in_edge[N];
namespace trie
{int p[N],t,fa[N][18],deep[N],dfn[N],cnt;struct data{int to,nxt;}edge[N];void clear(){memset(p,0,sizeof(p));cnt=t=0;}void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}void dfs(int k){dfn[k]=++cnt;for (int i=p[k];i;i=edge[i].nxt){deep[edge[i].to]=deep[k]+1;fa[edge[i].to][0]=k;dfs(edge[i].to);}}void build(){fa[1][0]=1;dfs(1);for (int j=1;j<18;j++)for (int i=1;i<=k;i++)fa[i][j]=fa[fa[i][j-1]][j-1];}int lca(int x,int y){if (deep[x]<deep[y]) swap(x,y);for (int j=17;~j;j--) if (deep[fa[x][j]]>=deep[y]) x=fa[x][j];if (x==y) return x;for (int j=17;~j;j--) if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];return fa[x][0];}
}
namespace graph
{int p[N<<6],t,cnt,dis[N<<6];bool flag[N<<6];struct data{int to,nxt,len;}edge[N<<7];struct data2{int x,d;bool operator <(const data2&a) const{return d>a.d;}};priority_queue<data2> q;void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=z,p[x]=t;}void clear(){cnt=n+m*2;t=0;memset(p,0,sizeof(p));}void dijkstra(){for (int i=1;i<=cnt;i++) dis[i]=inf;dis[1]=0;memset(flag,0,sizeof(flag));q.push((data2){1,0});for (;;){while (!q.empty()&&flag[q.top().x]) q.pop();if (q.empty()) break;data2 x=q.top();q.pop();flag[x.x]=1;for (int i=p[x.x];i;i=edge[i].nxt)if (dis[x.x]+edge[i].len<dis[edge[i].to]){dis[edge[i].to]=dis[x.x]+edge[i].len;q.push((data2){edge[i].to,dis[edge[i].to]});}}}
}
namespace virtual_tree
{int a[N],tot,stk[N],id[N<<1],top,p[N],x[N],y[N],idin[N<<1],idout[N<<1],pre[N<<1],suf[N<<1],t,cnt;struct data{int to,nxt;}edge[N<<1];void addedge(int u,int v){t++;x[t]=u,y[t]=v;}void clear(){tot=top=t=cnt=0;}void push(int x){a[++tot]=x;}bool cmp(const int&a,const int&b){return trie::dfn[a]<trie::dfn[b];}void dfs(int k){id[++cnt]=k;idin[k]=graph::cnt+cnt;for (int i=p[k];i;i=edge[i].nxt){dfs(edge[i].to);id[++cnt]=k;}}void build(){if (tot==0) return;sort(a+1,a+tot+1,cmp);tot=unique(a+1,a+tot+1)-a-1;stk[++top]=1;for (int i=1+(a[1]==1);i<=tot;i++){int l=trie::lca(a[i],stk[top]);if (stk[top]!=l){while (top>1&&trie::deep[stk[top-1]]>=trie::deep[l]) addedge(stk[top-1],stk[top]),top--;if (stk[top]!=l) addedge(l,stk[top]);stk[top]=l;}stk[++top]=a[i];}while (top>1) addedge(stk[top-1],stk[top]),top--;for (int i=1;i<=t;i++) p[x[i]]=p[y[i]]=0;for (int i=1;i<=t;i++) edge[i].to=y[i],edge[i].nxt=p[x[i]],p[x[i]]=i;dfs(1);for (int i=1;i<=cnt;i++) idout[id[i]]=idin[id[i]]+cnt;graph::cnt+=cnt<<1;for (int i=1;i<=cnt;i++){pre[i]=++graph::cnt;graph::addedge(idin[id[i]],pre[i],0);if (i>1) graph::addedge(pre[i-1],pre[i],0);}for (int i=cnt;i>=1;i--){suf[i]=++graph::cnt;graph::addedge(suf[i],idout[id[i]],0);if (i<cnt) graph::addedge(suf[i],suf[i+1],0);}for (int i=1;i<=cnt;i++) graph::addedge(pre[i],suf[i],trie::deep[id[i]]);for (int i=1;i<=cnt;i++){pre[i]=++graph::cnt;graph::addedge(pre[i],idout[id[i]],0);if (i>1) graph::addedge(pre[i],pre[i-1],0);}for (int i=cnt;i>=1;i--){suf[i]=++graph::cnt;graph::addedge(idin[id[i]],suf[i],0);if (i<cnt) graph::addedge(suf[i+1],suf[i],0);}for (int i=1;i<=cnt;i++) graph::addedge(suf[i],pre[i],trie::deep[id[i]]);}
}
int main()
{
#ifndef ONLINE_JUDGEfreopen("bzoj4912.in","r",stdin);freopen("bzoj4912.out","w",stdout);const char LL[]="%I64d\n";
#elseconst char LL[]="%lld\n";
#endifT=read();while (T--){n=read(),m=read(),k=read();memset(p,0,sizeof(p));t=0;for (int i=1;i<=n;i++) in_edge[i].clear();for (int i=1;i<=m;i++){int x=read(),y=read(),len=read(),s=read();t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=len,edge[t].s=s,p[x]=t;}trie::clear();for (int i=1;i<k;i++){int x=read(),y=read(),z=read();trie::addedge(x,y);}trie::build();graph::clear();for (int i=p[1];i;i=edge[i].nxt)graph::addedge(1,out(i),0);for (int i=1;i<=m;i++) if (edge[i].to!=1) graph::addedge(in(i),edge[i].to,0);for (int i=1;i<=m;i++) graph::addedge(out(i),in(i),edge[i].len);for (int i=1;i<=m;i++) in_edge[edge[i].to].push_back(i);for (int i=1;i<=n;i++){virtual_tree::clear();for (int j=0;j<in_edge[i].size();j++) virtual_tree::push(edge[in_edge[i][j]].s);for (int j=p[i];j;j=edge[j].nxt) virtual_tree::push(edge[j].s);virtual_tree::build();for (int j=0;j<in_edge[i].size();j++) graph::addedge(in(in_edge[i][j]),virtual_tree::idin[edge[in_edge[i][j]].s],0);for (int j=p[i];j;j=edge[j].nxt) graph::addedge(virtual_tree::idout[edge[j].s],out(j),0);}graph::dijkstra();for (int i=2;i<=n;i++) printf("%d\n",graph::dis[i]);}return 0;
}

  

转载于:https://www.cnblogs.com/Gloid/p/10347036.html

BZOJ4912 SDOI2017天才黑客(最短路+虚树)相关推荐

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

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

  2. [SDOI2017]天才黑客

    传送门 Description 给出一张带边权的有向图,每个边都上都有一个字符串(给出对应Trie树上的节点),一条路径的长度为路径上的边权之和+相邻两条边的字符串的lcp长度之和. 求从1到其它节点 ...

  3. 【SDOI2017】天才黑客

    [SDOI2017]天才黑客 这题太神了. 先模Claris 大神的题解. 首先我们要将边转换为点.如果暴力连边就会有\(m^2\)的边,于是我们考虑优化建图. 难点在于快速得到两个边的串的\(lcp ...

  4. 2020牛客NOIP赛前集训营-提高组(第三场)C-牛半仙的妹子Tree【虚树,最短路】

    正题 题目链接:https://ac.nowcoder.com/acm/contest/7609/C 题目大意 给出nnn个点的一棵树,mmm个时刻各有一个操作 标记一个点,每个点被标记后的每一个时刻 ...

  5. 【周末狂欢赛7】【NOIP模拟赛】七夕祭,齿轮(dfs),天才黑客

    文章目录 T1 题目 题解 code T2 题目 题解 code T3 题目 题解 code T1 题目 七夕节因牛郎织女的传说而被扣上了「情人节」的帽子.于是TYVJ今年举办了一次线下七夕祭.Van ...

  6. 2020牛客多校第一场B虚树+质数筛+换根dp

    题目大意: 1.可以发现阶乘增长是很快的所以你要把整颗树建立出来是不实际的. 2.我们可以假设这棵树已经建出来出来了我们应该怎么搞 首先很明显是一个树形dp, 我们设dp[j],是以j为u到其他点距离 ...

  7. 天才黑客 Flanker 疑因拒绝做黑客被拼多多强行辞退

    整理 | 王晓曼 出品 | 程序人生 (ID:coder _life) 1月12日,"如何看待天才黑客Flanker疑因拒绝做黑客攻击业务,被拼多多强行辞退,错失上亿股票?"的话题 ...

  8. [WC2018]通道——边分治+虚树+树形DP

    题目链接: [WC2018]通道 题目大意:给出三棵n个节点结构不同的树,边有边权,要求找出一个点对(a,b)使三棵树上这两点的路径权值和最大,一条路径权值为路径上所有边的边权和. 我们按照部分分逐个 ...

  9. Codeforces.809E.Surprise me!(莫比乌斯反演 虚树)

    题目链接 \(Description\) 给定一棵树,求\[\frac{1}{n(n-1)/2}\times\sum_{i\in[1,n],j\in[1,n],i\neq j}\varphi(a_i\ ...

最新文章

  1. 全国计算机在线做题,2020全国一级计算机基础及MS Office应用考试在线自测试题库(不限设备,登陆即可做题)...
  2. ihtml2document能不能根据id获取dom_回到基础:什么是DOM及DOM操作?
  3. Spark入门(四)Idea远程提交项目到spark集群
  4. 信息学奥赛一本通 2065:【例2.2】整数的和
  5. matlab中符号对象的数据类型是,符号对象(Symbolic Object)的使用
  6. ML面试1000题系列(91-100)
  7. STM32F429HAL库UART学习笔记
  8. URDGN:Ultra-resolve Face Images by Discriminative Generative Networks
  9. 中山大学delphi视频下载(51讲)
  10. 查看单元测试用例覆盖率新姿势:IDEA 集成 JaCoCo
  11. 741. 斐波那契数列
  12. MySQL 常用命令汇总
  13. Eclipse Mars2在线安装svn详细步骤
  14. 构成计算机系统物理实体的是什么,什么构成计算机的物理实体
  15. Chapter 5 (Eigenvalues and Eigenvectors): The characteristic equation (特征方程)
  16. 2017 LARS:LARGE BATCH TRAINING OF CONVOLUTIONAL NETWORKS (训练大Batch的卷积神经网络)
  17. ConnectBot的使用
  18. python输出时怎么保留两位小数_python输出怎么保留两位小数-Python教程
  19. 利用LDA分析《天龙八部》中每十回的话题演变情况
  20. ios nslog 例子_iOS Runtime常用示例总结

热门文章

  1. 计算方法之迭代法求方程根
  2. 让僵冷的翅膀飞起来—从实例谈OOP、工厂模式和重构[by Wayfarer]
  3. 图解基于 Node.js 实现前后端分离 - CSDN博客
  4. JavaScript 面向对象的程序设计1
  5. http --- http与https相关概念小结
  6. 读书笔记 --- [基础知识点] 小结3
  7. 一个go1.9.x 编译器内联引起的栈信息错乱的问题分析
  8. springCloud Finchley 实战入门(基于springBoot 2.0.3)【三 Eureka-高可用服务注册中心】...
  9. 云计算:容器技术变革云计算,SaaS带动CaaS市场
  10. 转:MAC 下安装PHONEGAP开发环境