【做题】Codeforces Round #436 (Div. 2) F. Cities Excursions——图论+dfs
题意:给你一个有向图,多次询问从一个点到另一个点字典序最小的路径上第k个点。
考虑枚举每一个点作为汇点(记为i),计算出其他所有点到i的字典序最小的路径。(当然,枚举源点也是可行的)
首先,我们建一张反向图,从i开始dfs,以删去所有无法到达i的点。
然后,因为此时图上所有点都可以到达i,所以可以贪心地在从每一个点出发的边中只保留终点编号最小的边,而把其他边删除。
这样就可以保证路径是字典序最小的,并且从每个点到i的路径只有一条。
而题目中给出了这样一种情况:
- there are paths from sj to tj, but for every such path p there is another path q from sj to tj, such that pi > qi, where i is the minimum integer for which pi ≠ qi.
因此最后可能某些未被删去的点无法到达i,就需要从i开始再dfs一遍,以删去这些点。
在最后这次dfs的同时通过倍增记录路径(即祖先节点),以实现O(logn)地查询路径的第k个点。
时间复杂度O(n^2*logn+q*logn)。
#include <bits/stdc++.h>
#define travel(i,x,p) for(int i=p.fir[(x)];i;i=p.con[i].la)
#define nex(x,p) p.con[x].b
using namespace std;
const int N=,Q=;
struct edge{
int la,b;
};
struct graph{
edge con[N];
int tot,fir[N];
bool vis[N];
void init()
{
tot=;
memset(fir,,sizeof fir);
}
void add(int from,int to)
{
con[++tot].la=fir[from];
con[tot].b=to;
fir[from]=tot;
}
void dfs(int pos)
{
vis[pos]=;
for(int i=fir[pos];i;i=con[i].la)
{
if(!vis[con[i].b]) dfs(con[i].b);
}
}
}p1,p2,p3;
int n,m,q,anc[N][];
struct query{
int s,k,id;
};
vector<query>ask[N];
int ans[Q];
void exdfs(int pos)
{
p3.vis[pos]=;
for(int i=;i<=;i++)
anc[pos][i]=anc[anc[pos][i-]][i-];
for(int i=p3.fir[pos];i;i=p3.con[i].la)
{
anc[p3.con[i].b][]=pos;
exdfs(p3.con[i].b);
}
}
void doit(query tmp,int pos)
{
if(!p3.vis[tmp.s]) ans[tmp.id]=-;
else
{
tmp.k--;
pos=tmp.s;
for(int i=;i>=;i--)
{
if((<<i)<=tmp.k)
tmp.k-=(<<i),pos=anc[pos][i];
}
if(pos==) ans[tmp.id]=-;
else ans[tmp.id]=pos;
}
}
void solve(int pos)
{
memset(p2.vis,,sizeof p2.vis);
p2.dfs(pos);
p3.init();
int tmp;
for(int i=;i<=n;i++)
{
if(p2.vis[i]&&i!=pos)
{
tmp=n+;
travel(j,i,p1)
{
if(p2.vis[nex(j,p1)]&&nex(j,p1)<tmp)
tmp=nex(j,p1);
}
if(tmp!=n+) p3.add(tmp,i);
}
}
memset(p3.vis,,sizeof p3.vis);
memset(anc,,sizeof(anc));
exdfs(pos);
for(int i=;i<(int)ask[pos].size();i++)
{
doit(ask[pos][i],pos);
}
}
int main()
{
int from,to;
scanf("%d%d%d",&n,&m,&q);
for(int i=;i<=m;i++)
{
scanf("%d%d",&from,&to);
p1.add(from,to);
p2.add(to,from);
}
int x,y,k;
for(int i=;i<=q;i++)
{
scanf("%d%d%d",&x,&y,&k);
ask[y].push_back((query){x,k,i});
}
for(int i=;i<=n;i++)
solve(i);
for(int i=;i<=q;i++)
printf("%d\n",ans[i]);
return ;
}
小结:在诸如最小字典序路径和其他问题中,可以通过预处理以保证贪心的正确性。
【做题】Codeforces Round #436 (Div. 2) F. Cities Excursions——图论+dfs的更多相关文章
- Codeforces Round #436 (Div. 2)【A、B、C、D、E】
Codeforces Round #436 (Div. 2) 敲出一身冷汗...感觉自己宛如智障:( codeforces 864 A. Fair Game[水] 题意:已知n为偶数,有n张卡片,每张 ...
- Codeforces Round #485 (Div. 2) F. AND Graph
Codeforces Round #485 (Div. 2) F. AND Graph 题目连接: http://codeforces.com/contest/987/problem/F Descri ...
- Codeforces Round #486 (Div. 3) F. Rain and Umbrellas
Codeforces Round #486 (Div. 3) F. Rain and Umbrellas 题目连接: http://codeforces.com/group/T0ITBvoeEx/co ...
- Codeforces Round #501 (Div. 3) F. Bracket Substring
题目链接 Codeforces Round #501 (Div. 3) F. Bracket Substring 题解 官方题解 http://codeforces.com/blog/entry/60 ...
- Codeforces Round #499 (Div. 1) F. Tree
Codeforces Round #499 (Div. 1) F. Tree 题目链接 \(\rm CodeForces\):https://codeforces.com/contest/1010/p ...
- 水题 Codeforces Round #308 (Div. 2) A. Vanya and Table
题目传送门 /* 水题:读懂题目就能做 */ #include <cstdio> #include <iostream> #include <algorithm> ...
- 水题 Codeforces Round #105 (Div. 2) B. Escape
题目传送门 /* 水题:这题唯一要注意的是要用double,princess可能在一个小时之内被dragon赶上 */ #include <cstdio> #include <alg ...
- 水题 Codeforces Round #302 (Div. 2) A Set of Strings
题目传送门 /* 题意:一个字符串分割成k段,每段开头字母不相同 水题:记录每个字母出现的次数,每一次分割把首字母的次数降为0,最后一段直接全部输出 */ #include <cstdio> ...
- 水题 Codeforces Round #299 (Div. 2) A. Tavas and Nafas
题目传送门 /* 很简单的水题,晚上累了,刷刷水题开心一下:) */ #include <bits/stdc++.h> using namespace std; ][] = {" ...
随机推荐
- html5-css渐变色
div{ width: 300px; height: 100px; margin: 50px; padding: 50px; border:5px groove rgba ...
- 读取文件任意位置的内容——RandomAccessFile
http://www.cnblogs.com/Sunw/p/3801145.html http://www.cnblogs.com/dukc/p/4776868.html http://www.cnb ...
- Explorer Bo (思维 + 树链剖分)
题意:求用最少的链覆盖所有的边用最少的总链长度. 思路:为了使得使用的链最少,我们可以知道使用的数量应该是(子叶 + 1)/ 2. 画图可知:当节点下的边数是偶数时,为了将该父节点上的边给连接上,所以 ...
- JavaScript 基础,登录验证
1.<script></script>的三种用法: a.放在<body>中 b.放在<head>中 c.放在外部JS文件中 <!DOCTYPE h ...
- Spark学习之路 (十六)SparkCore的源码解读(二)spark-submit提交脚本
一.概述 上一篇主要是介绍了spark启动的一些脚本,这篇主要分析一下Spark源码中提交任务脚本的处理逻辑,从spark-submit一步步深入进去看看任务提交的整体流程,首先看一下整体的流程概要图 ...
- Spring 无缝整合 quartz
关键步骤: 1. 配置 SchedulerFactoryBean <bean class="org.springframework.scheduling.quartz.Schedule ...
- rabbitmq和redis用作消息队列的区别
将redis发布订阅模式用做消息队列和rabbitmq的区别: 可靠性redis :没有相应的机制保证消息的可靠消费,如果发布者发布一条消息,而没有对应的订阅者的话,这条消息将丢失,不会存在内存中:r ...
- flask 单个表单多个提交按钮
单个表单多个提交按钮 在某些情况下,可能需要为一个表单添加多个提交按钮.比如在创建文章的表单中添加发布按钮和存草稿的按钮.当用户提交表单时,需要在视图函数中根据按下的按钮来做出不同的处理. 下面例子中 ...
- django -- 修改admin 密码问题
1.python manage.py shell 2.from django.contrib.auth.models import User 3.user=User.objects.get(usern ...
- HDU 2064 汉诺塔III (递推)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2064 约19世纪末,在欧州的商店中出售一种智力玩具,在一块铜板上有三根杆,最左边的杆上自上而下.由小到 ...