【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】天才黑客的更多相关文章

  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. bzoj 4912: [Sdoi2017]天才黑客

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

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

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

随机推荐

  1. [android] 绑定方式开启服务&调用服务的方法

    需求:后台开启一个唱歌服务,这个服务里面有个方法切换歌曲 新建一个SingService继承系统Service 重写onCreate()和onDestory()方法 填一个自定义的方法changeSi ...

  2. 4.3 explain 之 type

    一.explain 的type类型 二.类型的排序 从最好到最差依次是: system > const > eq_ref > ref > range > index &g ...

  3. Java Spring cron表达式使用详解

    Java Spring cron表达式使用详解   By:授客 QQ:1033553122 语法格式 Seconds Minutes Hours DayofMonth Month DayofWeek ...

  4. PHP全路径无限分类原理

    全路径无限分类:以一个字段把他所有的父级id按顺序记录下来以此实现的无限分类叫做全路径无限分类 优点:查询方便 缺点:增加,移动分类时数据维护时稍微复杂.

  5. 51NOD 1185 威佐夫游戏 V2(威佐夫博弈)

    1185 威佐夫游戏 V2  基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 有2堆石子.A B两个人轮流拿,A先拿.每次可以从一堆中取任意个或从2堆中取 ...

  6. mssql-sqlserver入门必备知识收集

    一.了解SQL 数据库的应用场景 sql 简介 二. 检索数据 SELECT语句    检索单个.多及所有列的方法分享 检索不同的值   限制结果   sqlserver注释编写方法 三.排序检索数据 ...

  7. JavaWeb 过滤器——验证登录 防止未登录进入界面

    昨天刚刚完成老师布置的一个Web小项目,项目中用到了两个过滤器(编码过滤.登录过滤) 比如电商网页中有些不需要登录也能访问(首页.商品详细信息...),其他都需要过滤在会话作用域(session)中是 ...

  8. Oracle EBS json

    JSON:  JavaScript 对象表示法 JavaScript Object Notation JSON 是存储和交换文本信息的语法.类似XML. JSON 比 XML更小.更快,更易解析. 使 ...

  9. The operation could not be performed because OLE DB provider "SQLNCLI11" for linked server "SDSSDFCC...

    The operation could not be performed because OLE DB provider "SQLNCLI11" for linked server ...

  10. 大话C#之委托

    开篇先来扯下淡,上篇博客LZ在结尾说这篇博客会来说说C#中的事件.但是当LZ看完事件之后发现事件是以委托为基础来实现的,于是LZ就自作主张地在这篇博客中先来说说委托,还烦请各位看官见谅!!!另外关于委 ...