某校内题 rain

Task 3. 雨中冒险
( rain.cpp/c/pas)
【 问题描述】
有 n 个节点,标号为 1..n。 m 条双向公路连接着这些节点,其中第 i 条公路
连接着 u_i 和 v_i,从一端走到另一端需要 w_i 秒。现在,小 Y 打算从学校回到
家里。
学校是节点 1,小 Y 家是节点 n,保证存在至少一条从节点 1 到节点 n 的路
径。
在第 0 秒,小 Y 身处节点 1,他的目标是尽早到达节点 n。根据天气预报,
接下来会有 k 次暴雨,第 i 次暴雨的时间为第 l_i 秒至第 r_i 秒,保证每次暴雨
的时间段互不重叠(包括起止时间)。由于小 Y 忘了带伞,因此在下雨期间,他
只能躲在某个节点里面避雨。如果某一个时刻在下暴雨,而小 Y 还在某条公路上,
那么他会被淋惨。
为了帮助小 Y 尽快回到家,上帝决定实现小 Y 一个愿望。小 Y 可以指定某一
条道路,然后这条道路两端的节点将合并成一个节点(合并出的节点拥有原来两
个节点的所有出边)。
请你帮小 Y 计算,在不被淋惨的前提下最早第多少秒他能回到自己家中?
注:对于一场第 l..r 秒的暴雨,若小 Y 第 r 秒从节点出发,或者第 l 秒到
达某个节点,那么他是不会淋到雨的。
【输入】
输入文件名: rain.in
第一行三个数 n、 m、 k。
接下来 m 行,第 i 行三个整数表示 u_i、 v_i、 w_i。
接下来 k 行,第 i 行两个整数表示 l_i、 r_i。
全国信息学奥林匹克联赛( NOIP2016)模拟赛 提高组 day1
【输出】
输出文件名: rain.out
第一行一个整数,表示小 Y 最早第多少秒能回到家中。
【数据范围】
测试点 1..6: k = 0
测试点 7..12: n、 m、 k≤10^3
测试点 1..20: 2≤n≤10^5, 1≤m≤2*10^5, 0≤k≤10^5, 1≤w_i≤10^4,
0≤l_i<r_i≤109,且保证输入的暴雨时间段互不相交、 l_i 严格递增。

这是一道挺不错的最短路题;

对于第一个部分分,对于每个点拆成两个点,分别表示用了缩边和没用缩边两种状态,相当于跑一个分层图最短路;

对于第二个部分分,首先仍是拆点,考虑如何处理下雨的情况:

比如从x到y距离为w,现在到x的最短路为dis;

于是相当于在dis后找到一段离dis最近的且长度为w的区间使其不被下雨天覆盖;

对于第二个部分分,可以暴力一场一场地等雨停然后判断从天晴后跑能否在下雨前跑到;

对于第三个部分分,我们要充分挖掘下雨的性质:

能走的时间是下雨间的间隙,对于第i场雨天晴后可走的时间是l[i+1]-r[i],记为rest[i];

那么上面那个问题转化为在dis后找到第一个一个大于等于w的rest[i],然后从r[i]开始走即可(特判一下不用等雨直接走的情况)

于是可以通过ST表+倍增求出找到第一个满足条件的雨后,然后开始转移即可(ST[j][i]表示从i走2^j场雨的最大值)

#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int gi()
{
   int x=0,flag=1;
   char ch=getchar();
   while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘) flag=-1;ch=getchar();}
   while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
   return x*flag;
}
const int N=200010;
const int M=1200010;
const int Inf=2147483647;
const int K=20;
int cnt,head[N],nxt[M],to[M],val[M],dis[N];
void lnk(int x,int y,int z){
  to[++cnt]=y,nxt[cnt]=head[x],val[cnt]=z,head[x]=cnt;
}
int l[N],r[N],ST[K][N],pre[K];
struct data{
  int x,d;
  bool operator <(const data b) const{return d>b.d;}
};
priority_queue <data> q;
bool vis[N];
int main(){
  freopen("rain.in","r",stdin);
  freopen("rain.out","w",stdout);
  pre[0]=1;for(int i=1;i<K;i++)pre[i]=pre[i-1]<<1;
  int n=gi(),m=gi(),k=gi();
  for(int i=1;i<=m;i++){
    int u=gi(),v=gi(),w=gi();
    lnk(u,v,w);lnk(v,u,w);
    lnk(u,n+v,0);lnk(v,n+u,0);
    lnk(n+u,n+v,w);lnk(n+v,n+u,w);
  }
  for(int i=1;i<=k;i++)l[i]=gi(),r[i]=gi();
  for(int i=1;i<k;i++)ST[0][i]=l[i+1]-r[i];ST[0][k]=10000;
  for(int j=1;j<K;j++)
    for(int i=1;i<=k;i++)
      ST[j][i]=max(ST[j-1][i],ST[j-1][i+pre[j-1]]);
  for(int i=1;i<=n;i++)dis[i]=dis[n+i]=Inf;
  dis[1]=0;
  q.push((data){1,0});
  while(!q.empty()){
    int x=q.top().x;q.pop();
    if(vis[x])continue;vis[x]=1;
    int last=upper_bound(r+1,r+k+1,dis[x])-r-1;
    for(int i=head[x];i;i=nxt[i]){
      int y=to[i];
      if(last==k||l[last+1]-dis[x]>=val[i]){
	if(dis[y]>dis[x]+val[i]) q.push((data){y,dis[y]=dis[x]+val[i]});
      }
      else{
	int nex=last+1;
	for(int j=K-1;j>=0;j--)
	  if(ST[j][nex]<val[i])nex+=pre[j];
	if(dis[y]>r[nex]+val[i]) q.push((data){y,dis[y]=r[nex]+val[i]});
      }
    }
  }
  printf("%d",min(dis[n],dis[n+n]));
  return 0;
}
时间: 2024-10-11 11:39:11

某校内题 rain的相关文章

LeetCode第[42]题(Java):Trapping Rain Water

题目:接雨水 难度:hard 题目内容: Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining. The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In

leetcode 第41题 Trapping Rain Water

题目: Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining. For example, Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6. The above elevation map is represented

【10.7校内测试】【队列滑窗】【2-sat】【贪心+栈二分+线段树(noip模拟好题)】【生日祭!】

比较好想的一道题,直接用队列滑窗,因为扫一遍往队列里加东西时,改变的只有一个值,开桶储存好就行了! #include<bits/stdc++.h> using namespace std; int n, k, r; inline int min(int a, int b) { return a > b ? b : a; } inline int max(int a, int b) { return a > b ? a : b; } int sum[200005], q[200005

刷题42. Trapping Rain Water

一.题目说明 题目是42. Trapping Rain Water,翻译起来就是"接雨水".给n个非负正数代表高度,每个正数宽度为1,让计算能多少雨水.题目难度是Hard 二.我的解法 这个题目是找"坑",然后计算里面可以存的"雨".总共提交了5次,前面几次都是边界错误. 代码如下: #include<iostream> #include<vector> using namespace std; class Solutio

2017.5 校内预选赛 第三题 ants poj1852

题目: http://poj.org/problem?id=1852 只要想到点子上,很简单. 以第一个栗子来解释: 10 3 2 6 7 按照题意 A B 相遇则A B 改变方向,其实可以看作A和B相遇穿过继续运动. 这样就最短时间 只要找到每个蚂蚁到一端的最短时间,然后找出其中的最大值 例如最短时间分别对应 2 4 3 所以结果为4 最长时间 就只要找出每个点的最长时间然后取最大值 代码如下(能够ac): #include<iostream> using namespace std; in

回文素数-2015校内选拔第三题

10301是个5位的素数.它有个特点,把数字倒过来还是它本身,具有这样特征的素数,我们称之为:回文素数. 105011060111311 这些都是5位的回文素数. 请你计算一下,像这样的5位数的回文素数,一共有多少个? 请填写这个表示个数的整数,注意不要写任何其它多余的内容,比如说明或解释文字,也不要列出所有的回文素数. 原文地址:https://www.cnblogs.com/jinyufanfan/p/10105434.html

第五届蓝桥杯全国软件设计大赛--2013年校内选拔赛Java题目

第五届蓝桥杯全国软件设计大赛 2013年校内选拔赛Java题目 一.考生注意: (1)[结果填空题]要求参赛选手根据题目描述直接填写结果.求解方式不限.不要求源代码. 把答案存入[考生文件夹]下对应题号的文件中即可. (2)[代码填空题]要求参赛选手在弄清给定代码工作原理的基础上填写缺失的部分,使得程序逻辑正确.完整.所填写的代码不超过一条语句(即中间不能出现分号). 把填空的答案(仅填空处的答案,不包括题面已存在的代码)存入[考生文件夹]下对应题号的文件中中即可. (3)[编程题]要求选手设计

LeetCode——Trapping Rain Water

Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining. For example, Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6. The above elevation map is represented by a

二分图的一大泼基础题

[HDU]//1068 Girls and Boys 最大匹配★//1150 Machine Schedule 最小点覆盖★1151 Air Raid 最小路径覆盖★//1179 Ollivanders 最大匹配★1281 棋盘游戏 行列匹配+求关键点★★1498 50 years, 50 colors 行列匹配★1507 Uncle Tom's Inherited Land* 黑白染色+奇偶匹配(1X2的矩形覆盖)★//1528 Card Game Cheater 最大匹配★1845 Jimm