【BZOJ】4144: [AMPPZ2014]Petrol
2015-11-22 18:30
417 查看
题意
给定一个\(n\)个点、\(m\)条边的带权无向图,其中有\(s\)个点是加油站。每辆车都有一个油量上限\(b\),即每次行走距离不能超过\(b\),但在加油站可以补满。\(q\)次询问,每次给出\(x,y,b\),表示出发点是\(x\),终点是\(y\),油量上限为\(b\),且保证\(x\)点和\(y\)点都是加油站,请回答能否从\(x\)走到\(y\)。(\(2 \le s \le n \le 200000, 1 \le m \le 200000\))分析
首先来分析如果只有一个询问,给出\(x\)点和\(y\)点问\(x\)是否能走到\(y\)。假设经过的非加油站的点集依次是\(p_1, p_2, \cdots, p_k\),那么考虑从\(p_1\)走到\(p_2\),假设有边\((p_1, p_2)\)(否则一定是从加油站走到\(p_2\)的),权值为\(w\)。如果我们从\(p_1\)走到最近的加油站(距离为\(d(p_1)\))加满油再回来,还剩的油为\(b-d(p_1)\),然后再走这条边。而如果直接从\(p_1\)走到\(p_2\),由于没有加油,此时在\(p_1\)的油量显然是\(\le b-d(p_1)\)的。显然加了油更优。题解
根据分析,我们只需要按新赋值的边权w+d(u)+d(v)生成最小生成树来判断即可。对于询问,离线一下即可。#include <bits/stdc++.h> using namespace std; const int N=200005, M=200005; int ihead , cnt, n, m, s, p , h , c ; struct E { int next, to, w; }e[M<<1]; struct ED { int x, y, d; }ed[M]; struct QU { int x, y, b, id; }q ; void add(int x, int y, int w) { e[++cnt]=(E){ihead[x], y, w}; ihead[x]=cnt; e[++cnt]=(E){ihead[y], x, w}; ihead[y]=cnt; } int find(int x) { return x==p[x]?x:p[x]=find(p[x]); } typedef pair<int, int> pii; #define mkpii make_pair<int, int> priority_queue<pii, vector<pii>, greater<pii> > qu; int d , vis ; void dij() { memset(d, 0x7f, sizeof(int)*(n+1)); for(int i=0; i<s; ++i) { d[c[i]]=0; qu.push(mkpii(0, c[i])); } while(qu.size()) { int x=qu.top().second; qu.pop(); if(vis[x]) { continue; } vis[x]=1; for(int i=ihead[x]; i; i=e[i].next) { int y=e[i].to; if(d[y]>d[x]+e[i].w) { d[y]=d[x]+e[i].w; qu.push(mkpii(d[y], y)); } } } } inline bool cmp1(const ED &a, const ED &b) { return a.d<b.d; } inline bool cmp2(const QU &a, const QU &b) { return a.b<b.b; } int ans ; int main() { scanf("%d%d%d", &n, &s, &m); for(int i=1; i<=n; ++i) { p[i]=i; h[i]=1; } for(int i=0; i<s; ++i) { scanf("%d", &c[i]); } for(int i=0; i<m; ++i) { scanf("%d%d%d", &ed[i].x, &ed[i].y, &ed[i].d); add(ed[i].x, ed[i].y, ed[i].d); } dij(); for(int i=0; i<m; ++i) { ed[i].d+=d[ed[i].x]+d[ed[i].y]; } int Q; scanf("%d", &Q); for(int i=0; i<Q; ++i) { scanf("%d%d%d", &q[i].x, &q[i].y, &q[i].b); q[i].id=i; } sort(ed, ed+m, cmp1); sort(q, q+Q, cmp2); int now=0; for(int i=0; i<Q; ++i) { while(now<m && ed[now].d<=q[i].b) { int fx=find(ed[now].x), fy=find(ed[now].y); if(fx!=fy) { if(h[fx]>h[fy]) { swap(fx, fy); } p[fx]=fy; h[fy]+=h[fy]==h[fx]; } ++now; } ans[q[i].id]=find(q[i].x)==find(q[i].y); } for(int i=0; i<Q; ++i) { puts(ans[i]?"TAK":"NIE"); } return 0; }
相关文章推荐
- “南大软院大神养成计划“_第七天的学习“
- angular
- android 中Jsonobject里的键值是动态时,获得键值key
- PCA主成因分析法
- Ajax实现简单下拉选项
- learn go return fuction
- 【BZOJ】4056: [Ctsc2015]shallot
- HDU 2612 Find a way(bfs)
- Thinking in Google Doc-不同的Apps之间的交互
- 1317 相似字符串对
- CSS3 使用自定义字体
- matlab:逐个读取文件夹里以数字命名的图片
- HDU 5568 dp+大数板子
- OpenCV 2.4.11 VS2010 Configuration
- 支付宝手机网站支付私钥公钥生成(window环境)
- java从类路径下加载资源文件
- 反向代理的概念
- Using Caliburn.Micro (version 2) for WPF development
- c#中调用存储过程示例
- Can not find the tag library descriptor for “http://java.sun.com/jsp/jstl/core