【BZOJ】【4144】【AMPPZ2014】Petrol

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



  图论问题中综合性较强的一题= =(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一次啊!!!

  1 /**************************************************************
  2     Problem: 4144
  3     User: Tunix
  4     Language: C++
  5     Result: Accepted
  6     Time:5076 ms
  7     Memory:51424 kb
  8 ****************************************************************/
  9
 10 //BZOJ 4144
 11 #include<vector>
 12 #include<queue>
 13 #include<cstdio>
 14 #include<cstring>
 15 #include<cstdlib>
 16 #include<iostream>
 17 #include<algorithm>
 18 #define rep(i,n) for(int i=0;i<n;++i)
 19 #define F(i,j,n) for(int i=j;i<=n;++i)
 20 #define D(i,j,n) for(int i=j;i>=n;--i)
 21 using namespace std;
 22 typedef long long LL;
 23 inline int getint(){
 24     int r=1,v=0; char ch=getchar();
 25     for(;!isdigit(ch);ch=getchar()) if (ch==‘-‘) r=-1;
 26     for(; isdigit(ch);ch=getchar()) v=v*10-‘0‘+ch;
 27     return r*v;
 28 }
 29 const int N=2e5+10,INF=~0u>>1;
 30 /*******************template********************/
 31
 32 int head[N],to[N<<1],nxt[N<<1],l[N<<1],cnt;
 33 void ins(int x,int y,int z){
 34     to[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt; l[cnt]=z;
 35 }
 36 struct edge{
 37     int x,y,w;
 38     bool operator < (const edge &b)const {return w<b.w;}
 39 }E[N<<1];
 40 int n,m,s,dis[N],from[N],c[N];
 41
 42
 43 int f[N],sz[N];
 44 inline int getf(int x){return f[x]==x?x:getf(f[x]);}
 45 typedef pair<int,int> pii;
 46 #define fi first
 47 #define se second
 48 #define mp make_pair
 49 priority_queue<pii,vector<pii>,greater<pii> >Q;
 50 bool vis[N];
 51 void dij(){
 52     F(i,1,n) dis[i]=INF;
 53     F(i,1,s){
 54         dis[c[i]]=0;
 55         from[c[i]]=c[i];
 56         Q.push(mp(0,c[i]));
 57     }
 58     while(!Q.empty()){
 59         int x=Q.top().se; Q.pop();
 60         if (vis[x]) continue;
 61         vis[x]=1;
 62         for(int i=head[x];i;i=nxt[i])
 63             if (dis[to[i]]>dis[x]+l[i]){
 64                 dis[to[i]]=dis[x]+l[i];
 65                 from[to[i]]=from[x];
 66                 Q.push(mp(dis[to[i]],to[i]));
 67             }
 68     }
 69     int tot=0;
 70     F(i,1,m){
 71         int x=to[i*2-1],y=to[i<<1];
 72         if (from[x]!=from[y])
 73             E[++tot]=(edge){from[x],from[y],dis[x]+dis[y]+l[i<<1]};
 74     }
 75     sort(E+1,E+tot+1);
 76     memset(head,0,sizeof head); cnt=0;
 77     F(i,1,n) f[i]=i,sz[i]=1;
 78     F(i,1,tot){
 79         int f1=getf(E[i].x),f2=getf(E[i].y);
 80         if (f1!=f2){
 81             if (sz[f1]>sz[f2]) swap(f1,f2);
 82             f[f1]=f2;
 83             sz[f2]+=sz[f1];
 84             ins(E[i].x,E[i].y,E[i].w);
 85             ins(E[i].y,E[i].x,E[i].w);
 86         }
 87     }
 88 }
 89
 90 int fa[N][20],dep[N],mx[N][20],num,belong[N];
 91 void dfs(int x,int num){
 92     belong[x]=num;
 93     F(i,1,19)
 94         if (dep[x]>=(1<<i)){
 95             fa[x][i]=fa[fa[x][i-1]][i-1];
 96             mx[x][i]=max(mx[x][i-1],mx[fa[x][i-1]][i-1]);
 97         }else break;
 98     for(int i=head[x];i;i=nxt[i])
 99         if (to[i]!=fa[x][0]){
100             fa[to[i]][0]=x;
101             dep[to[i]]=dep[x]+1;
102             mx[to[i]][0]=l[i];
103             dfs(to[i],num);
104         }
105 }
106 int query(int x,int y){
107     if (dep[x]<dep[y]) swap(x,y);
108     int t=dep[x]-dep[y],ans=0;
109     F(i,0,19) if (t&(1<<i)) ans=max(ans,mx[x][i]),x=fa[x][i];
110     D(i,19,0)
111         if (fa[x][i]!=fa[y][i])
112             ans=max(ans,max(mx[x][i],mx[y][i])),
113             x=fa[x][i],y=fa[y][i];
114     if (fa[x][0]!=fa[y][0]) return 0;
115     if (x!=y) ans=max(ans,max(mx[x][0],mx[y][0]));
116     return ans;
117 }
118 int main(){
119 #ifndef ONLINE_JUDGE
120     freopen("4144.in","r",stdin);
121     freopen("4144.out","w",stdout);
122 #endif
123     n=getint(); s=getint(); m=getint();
124     F(i,1,s) c[i]=getint();
125     F(i,1,m){
126         int x=getint(),y=getint(),z=getint();
127         ins(x,y,z); ins(y,x,z);
128     }
129     dij();
130     memset(vis,0,sizeof vis);
131     F(i,1,s) if (!belong[c[i]]) dfs(c[i],++num);
132     int q=getint();
133     while(q--){
134         int x=getint(),y=getint(),z=getint();
135         if (belong[x]!=belong[y]) puts("NIE");
136         else puts((query(x,y)<=z) ? "TAK" : "NIE");
137     }
138     return 0;
139 }

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

鸣谢Claris上传

[Submit][Status][Discuss]

时间: 2024-10-06 14:15:29

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

【BZOJ 2754 喵星球上的点名】

Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2512  Solved: 1092[Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到. 然而,由于喵星人的字

【BZOJ 2820】 YY的GCD

2820: YY的GCD Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 807  Solved: 404 [Submit][Status] Description 神犇YY虐完数论后给傻×kAc出了一题 给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对 kAc这种傻×必然不会了,于是向你来请教-- 多组输入 Input 第一行一个整数T 表述数据组数 接下来T行,每行两个正整数,表示

【BZOJ】3319: 黑白树

http://www.lydsy.com/JudgeOnline/problem.php?id=3319 题意:给一棵n节点的树(n<=1e6),m个操作(m<=1e6),每次操作有两种:1.查询u到根的第一条黑边的编号.2.将u到v的路径全部染成黑色 #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream>

P2433 - 【BZOJ 3262三维偏序】陌上花开------三维偏序

P2433 - [BZOJ 3262三维偏序]陌上花开 Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量. 定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb.显然,两朵花可能有同样的属性.需要统计出评出每个等级的花的数量. Input 第一行为N,K (1 <= N <= 100,000, 1 <= K <= 200,

【bzoj】4538: [Hnoi2016]网络

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4538 维护一个数据结构支持对于一颗树的操作,需要支持: 1.对于树上的一条路径上的每个点上放一个值. 2.撤销某次操作的路劲放. 3.查询除了经过这个点的路径的最大值. 往一个路径上丢值相当于往不经过条路径的所有点上丢值. 用一个树链剖分即可维护,对于操作区间取反. 直接查询单点最大值即可. 为了维护单点最大值,线段树中的每一个点对应两个堆,用于维护插入誉删除. 防止爆空间,所以标记永久

【BZOJ】1821: [JSOI2010]Group 部落划分 Group(最小生成树+贪心)

http://www.lydsy.com:808/JudgeOnline/problem.php?id=1821 这题裸题. 本题要求最短距离最长,很明显,我们排序. 这里存在贪心,即我们把边权最小的全分给n个部落的内部,然后剩下的边最小的就是答案. 将边权较小的边分给k个部落,用并查集生成最小树,使得内部的边总是小于连到外部的边.然后分剩下k个点即可,剩下的k个点的那条边一定是部落之间最小的且最长的边. #include <cstdio> #include <cstring> #

【BZOJ】【1415】【NOI2005】聪聪和可可

数学期望+记忆化搜索 论文:<浅析竞赛中一类数学期望问题的解决方法>——汤可因  中的第一题…… Orz 黄学长 我实在是太弱,这么简单都yy不出来…… 宽搜预处理有点spfa的感觉= =凡是更新了的,都要重新入队更新一遍…… dp的记忆化搜索过程好厉害…… 期望这里一直很虚啊,赶紧再多做点题熟悉熟悉…… 1 /************************************************************** 2 Problem: 1415 3 User: Tunix

【BZOJ】【3083】遥远的国度

树链剖分/dfs序 其实过了[BZOJ][4034][HAOI2015]T2以后就好搞了…… 链修改+子树查询+换根 其实静态树的换根直接树链剖分就可以搞了…… 因为其实只有一样变了:子树 如果root在x的子树中(以1为根dfs的时候),那么现在x的子树就变成了整个dfs序中,除去含有root的那个子树的剩下的部分,画个图大概就是这样:(红色部分为现在的子树) 我们发现,这种子树由于换根而产生变化的情况,仅当在以1为根时的树中,x是new_root的祖先时发生,那么我们判断这种情况是否发生只需

【BZOJ 1854】 [Scoi2010]游戏

1854: [Scoi2010]游戏 Time Limit: 5 Sec  Memory Limit: 162 MB Submit: 2609  Solved: 931 [Submit][Status] Description lxhgww最近迷上了一款游戏,在游戏里,他拥有很多的装备,每种装备都有2个属性,这些属性的值用[1,10000]之间的数表示.当他使用某种装备时,他只能使用该装备的某一个属性.并且每种装备最多只能使用一次. 游戏进行到最后,lxhgww遇到了终极boss,这个终极bos

【BZOJ】2301: [HAOI2011]Problem b(莫比乌斯+分块)

http://www.lydsy.com/JudgeOnline/problem.php?id=2301 和这题不是差不多的嘛--[BZOJ]1101: [POI2007]Zap(莫比乌斯+分块) 唯一不同的地方是这题有下界.. 下界除以k的时候取上界,然后分块的时候因为有4个数,所以要分成4块来搞.. 然后就行了.. #include <cstdio> #include <cstring> #include <cmath> #include <string>