最短路+最小生成树+倍增


  图论问题中综合性较强的一题= =(Orz vfk)

  比较容易发现,关键的还是有加油站的这些点,其他点都是打酱油的。

  也就是说我们重点是要求出 关键点之间的最短路

  这玩意……如果枚举加油站所在的点,然后跑单源最短路什么的……肯定TLE啊。

  我们记from[i]表示离 i 最近的关键点,仔细考虑一下,A->B的最短路径上,一定是前一半的from[i]为A,然后走过某条路以后,后一半的from[i]为B。为什么呢?我们不妨设中间出现了一个点x的from[x]=C,那么我们大可以从A走到C,加满油,再从C走到B,这样一定不会差!所以AB之间是否有边就看是否满足这样的条件了……

  做法是:先将所有关键点的dist置为0,丢到堆里面做dijkstra,求出每个点的dist和from,然后枚举每条边,如果它连接的两个点满足from[x]!=from[y],那么from[x]和from[y]这两个关键点之间的最短路就找到了。。。

  现在我们对只包含关键点的这张图做最小生成树,查询的时候倍增就可以了(又变成了货车运输。。。)

  小Trick:图可能不连通,考虑关键点的时候需要分连通块……我一开始光想着如果不在一个连通块内就为NIE,然而忘了既然是多个连通块,那就不能只dfs一次啊!!!

 /**************************************************************
Problem: 4144
User: Tunix
Language: C++
Result: Accepted
Time:5076 ms
Memory:51424 kb
****************************************************************/ //BZOJ 4144
#include<vector>
#include<queue>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
using namespace std;
typedef long long LL;
inline int getint(){
int r=,v=; char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-;
for(; isdigit(ch);ch=getchar()) v=v*-''+ch;
return r*v;
}
const int N=2e5+,INF=~0u>>;
/*******************template********************/ int head[N],to[N<<],nxt[N<<],l[N<<],cnt;
void ins(int x,int y,int z){
to[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt; l[cnt]=z;
}
struct edge{
int x,y,w;
bool operator < (const edge &b)const {return w<b.w;}
}E[N<<];
int n,m,s,dis[N],from[N],c[N]; int f[N],sz[N];
inline int getf(int x){return f[x]==x?x:getf(f[x]);}
typedef pair<int,int> pii;
#define fi first
#define se second
#define mp make_pair
priority_queue<pii,vector<pii>,greater<pii> >Q;
bool vis[N];
void dij(){
F(i,,n) dis[i]=INF;
F(i,,s){
dis[c[i]]=;
from[c[i]]=c[i];
Q.push(mp(,c[i]));
}
while(!Q.empty()){
int x=Q.top().se; Q.pop();
if (vis[x]) continue;
vis[x]=;
for(int i=head[x];i;i=nxt[i])
if (dis[to[i]]>dis[x]+l[i]){
dis[to[i]]=dis[x]+l[i];
from[to[i]]=from[x];
Q.push(mp(dis[to[i]],to[i]));
}
}
int tot=;
F(i,,m){
int x=to[i*-],y=to[i<<];
if (from[x]!=from[y])
E[++tot]=(edge){from[x],from[y],dis[x]+dis[y]+l[i<<]};
}
sort(E+,E+tot+);
memset(head,,sizeof head); cnt=;
F(i,,n) f[i]=i,sz[i]=;
F(i,,tot){
int f1=getf(E[i].x),f2=getf(E[i].y);
if (f1!=f2){
if (sz[f1]>sz[f2]) swap(f1,f2);
f[f1]=f2;
sz[f2]+=sz[f1];
ins(E[i].x,E[i].y,E[i].w);
ins(E[i].y,E[i].x,E[i].w);
}
}
} int fa[N][],dep[N],mx[N][],num,belong[N];
void dfs(int x,int num){
belong[x]=num;
F(i,,)
if (dep[x]>=(<<i)){
fa[x][i]=fa[fa[x][i-]][i-];
mx[x][i]=max(mx[x][i-],mx[fa[x][i-]][i-]);
}else break;
for(int i=head[x];i;i=nxt[i])
if (to[i]!=fa[x][]){
fa[to[i]][]=x;
dep[to[i]]=dep[x]+;
mx[to[i]][]=l[i];
dfs(to[i],num);
}
}
int query(int x,int y){
if (dep[x]<dep[y]) swap(x,y);
int t=dep[x]-dep[y],ans=;
F(i,,) if (t&(<<i)) ans=max(ans,mx[x][i]),x=fa[x][i];
D(i,,)
if (fa[x][i]!=fa[y][i])
ans=max(ans,max(mx[x][i],mx[y][i])),
x=fa[x][i],y=fa[y][i];
if (fa[x][]!=fa[y][]) return ;
if (x!=y) ans=max(ans,max(mx[x][],mx[y][]));
return ans;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("4144.in","r",stdin);
freopen("4144.out","w",stdout);
#endif
n=getint(); s=getint(); m=getint();
F(i,,s) c[i]=getint();
F(i,,m){
int x=getint(),y=getint(),z=getint();
ins(x,y,z); ins(y,x,z);
}
dij();
memset(vis,,sizeof vis);
F(i,,s) if (!belong[c[i]]) dfs(c[i],++num);
int q=getint();
while(q--){
int x=getint(),y=getint(),z=getint();
if (belong[x]!=belong[y]) puts("NIE");
else puts((query(x,y)<=z) ? "TAK" : "NIE");
}
return ;
}

4144: [AMPPZ2014]Petrol

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 83  Solved: 36
[Submit][Status][Discuss]

Description

给定一个n个点、m条边的带权无向图,其中有s个点是加油站。
每辆车都有一个油量上限b,即每次行走距离不能超过b,但在加油站可以补满。
q次询问,每次给出x,y,b,表示出发点是x,终点是y,油量上限为b,且保证x点和y点都是加油站,请回答能否从x走到y。

Input

第一行包含三个正整数n,s,m(2<=s<=n<=200000,1<=m<=200000),表示点数、加油站数和边数。
第二行包含s个互不相同的正整数c[1],c[2],...c[s](1<=c[i]<=n),表示每个加油站。
接下来m行,每行三个正整数u[i],v[i],d[i](1<=u[i],v[i]<=n,u[i]!=v[i],1<=d[i]<=10000),表示u[i]和v[i]之间有一条长度为d[i]的双向边。
接下来一行包含一个正整数q(1<=q<=200000),表示询问数。
接下来q行,每行包含三个正整数x[i],y[i],b[i](1<=x[i],y[i]<=n,x[i]!=y[i],1<=b[i]<=2*10^9),表示一个询问。

Output

输出q行。第i行输出第i个询问的答案,如果可行,则输出TAK,否则输出NIE。
 

Sample Input

6 4 5
1 5 2 6
1 3 1
2 3 2
3 4 3
4 5 5
6 4 5
4
1 2 4
2 6 9
1 5 9
6 5 8

Sample Output

TAK
TAK
TAK
NIE

HINT

Source

[Submit][Status][Discuss]

【BZOJ】【4144】【AMPPZ2014】Petrol的更多相关文章

  1. 【BZOJ 2754 喵星球上的点名】

    Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2512  Solved: 1092[Submit][Status][Discuss] Descript ...

  2. 【BZOJ】3052: [wc2013]糖果公园

    http://www.lydsy.com/JudgeOnline/problem.php?id=3052 题意:n个带颜色的点(m种),q次询问,每次询问x到y的路径上sum{w[次数]*v[颜色]} ...

  3. 【BZOJ】3319: 黑白树

    http://www.lydsy.com/JudgeOnline/problem.php?id=3319 题意:给一棵n节点的树(n<=1e6),m个操作(m<=1e6),每次操作有两种: ...

  4. 【BZOJ】3319: 黑白树(并查集+特殊的技巧/-树链剖分+线段树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=3319 以为是模板题就复习了下hld............................. 然后n ...

  5. 【BZOJ】【1025】【SCOI2009】游戏

    DP/整数拆分 整个映射关系可以分解成几个循环(置换群的预备知识?),那么总行数就等于各个循环长度的最小公倍数+1(因为有个第一行的1~N).那么有多少种可能的排数就等于问有多少种可能的最小公倍数. ...

  6. 【BZOJ】1013: [JSOI2008]球形空间产生器sphere

    [BZOJ]1013: [JSOI2008]球形空间产生器sphere 题意:给n+1个n维的点的坐标,要你求出一个到这n+1个点距离相等的点的坐标: 思路:高斯消元即第i个点和第i+1个点处理出一个 ...

  7. 【BZOJ】1002:轮状病毒(基尔霍夫矩阵【附公式推导】或打表)

    Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个N轮状基由圆环上N个不同的基原子和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道.如下图 ...

  8. 【BZOJ】【3697】采药人的路径&【3127】【USACO2013 Open】Yin and Yang

    点分治 Orz hzwer 倒是比较好想到点分治……然而在方案统计这里,我犯了两个错误…… 1.我比较傻逼的想的是:通过儿子来更新父亲,也就是统计以x为根的子树中xxxx的路径有多少条……这样转移. ...

  9. 【BZOJ】【3083】遥远的国度

    树链剖分/dfs序 其实过了[BZOJ][4034][HAOI2015]T2以后就好搞了…… 链修改+子树查询+换根 其实静态树的换根直接树链剖分就可以搞了…… 因为其实只有一样变了:子树 如果roo ...

  10. 【BZOJ】【2434】【NOI2011】阿狸的打字机

    AC自动机+DFS序+BIT 好题啊……orz PoPoQQQ 大爷 一道相似的题目:[BZOJ][3172][TJOI2013]单词 那道题也是在fail树上数有多少个点,只不过这题是在x的fail ...

随机推荐

  1. 018.Zabbix维护时间和模板导入

    一 维护时间 在某些正常业务维护期间,不需要进行告警,可添加维护时间. 二 维护时间添加 2.1 维护 参数 描述 Name 维护名称 Maintenance type 两种维护类型可选: With ...

  2. 【python学习-1】python环境设置与开发

    开始学习python,打算把学习过程都记下来. 下载python,虽然推荐官网,但是感觉官网上面下载python太慢,所以我最后是在csdn上面下载的python版本(3.2.4 windows 64 ...

  3. HDU 5810 Balls and Boxes 数学

    Balls and Boxes 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5810 Description Mr. Chopsticks is i ...

  4. Azure虚机磁盘容量警报(邮件提醒)

    上周有个客户提出这样的需求:根据虚拟机磁盘的实际使用量,当达到某一阈值时设置邮件提醒. 在这个需求中我们只需要解决两点问题: 计算虚拟机磁盘实际使用量 发送邮件 使用VS新建一个名为Calculate ...

  5. DIV+javascript实现首尾相连循环滚动效果

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. brew安装sshpass

    有以下解决方法: # 1 brew install https://raw.githubusercontent.com/kadwanev/bigboybrew/master/Library/Formu ...

  7. [原创]互联网金融App测试介绍

    [原创]互联网金融App测试介绍 前端时间非常忙,终于非常忙的时间过去了,抽时间总结下我现在所在公司理财软件App测试,也各位分享下,也欢迎大家提建议,谢谢! 先介绍下我所在公司的产品特点,公司所研发 ...

  8. SWD Connect/Transfer Source Code

    Serial Wire Debug interface The Serial Wire Debug protocol operates with a synchronous serial interf ...

  9. Understanding the STM32F0's GPIO

    Understanding the STM32F0's GPIO This is the first part of the GPIO tutorial for the STM32F0Discover ...

  10. 手把手教你使用C#操作SQLite数据库,新建数据库,创建表,插入,查询,删除,运算符,like

    目录: 一.新建项目,添加引用 二.创建数据库 三.创建表 四.插入数据  五.查询数据  六.删除数据  七.运算符 八.like语句 我的环境配置:windows 64,VS,SQLite(点击下 ...