2016北京集训测试赛(九)Problem C: 狂飙突进的幻想乡

Solution
我们发现, 对于一条路径来说, 花费总时间为\(ap + q\), 其中\(p\)和\(q\)为定值. 对于每个点, 我们有多条路径可以到达, 因此对于每个区间中的\(a\)我们可以找到不同的\(p\)和\(q\)使得答案最优. 因此对每个点维护一个凸包即可. 同时我们注意到\(0 \le a \le 1\), 因此凸包中的元素不会无限增长.
考虑如何构建这个凸包? SPFA即可. 具体实现见代码.
#include <cstdio>
#include <cctype>
#include <vector>
#include <deque>
#include <set>
#define vector std::vector
#define deque std::deque
#define set std::set
namespace Zeonfai
{
inline int getInt()
{
int a = 0, sgn = 1;
char c;
while(! isdigit(c = getchar())) if(c == '-') sgn *= -1;
while(isdigit(c)) a = a * 10 + c - '0', c = getchar();
return a * sgn;
}
}
const int N = 200;
int n, m, S, T;
struct point
{
int x, y;
inline point() {}
inline point(int _x, int _y) {x = _x; y = _y;}
inline int friend operator <(point a, point b) {return a.x == b.x ? a.y < b.y : a.x < b.x;}
inline int friend operator ==(point a, point b) {return a.x == b.x && a.y == b.y;}
};
double slope(point a, point b) {return a.x == b.x ? 1e50 : (double)(a.y - b.y) / (a. x - b.x);}
struct graph
{
struct node;
struct edge
{
node *v; int x, y;
inline edge(node *_v, int _x, int _y) {v = _v; x = _x; y = _y;}
};
struct node
{
vector<edge> edg;
set<point> st;
inline node() {edg.clear(); st.clear();}
inline int check(point p) {return st.find(p) != st.end();}
inline int insert(point p)
{
st.insert(p);
static point stk[N * N]; int tp = 0;
for(auto cur : st)
{
while(tp >= 2 && slope(stk[tp - 1], stk[tp - 2]) > slope(cur, stk[tp - 1])) -- tp;
while(tp >= 1 && slope(cur, stk[tp - 1]) < 0) -- tp;
if(! tp || slope(cur, stk[tp - 1]) <= 1) stk[tp ++] = cur;
}
st.clear();
for(int i = 0; i < tp; ++ i) st.insert(stk[i]);
return st.find(p) != st.end();
}
inline double getAnswer()
{
static point p[N * N]; int cnt = 0;
for(auto cur : st) p[cnt ++] = cur;
if(cnt == 0) return 0;
else if(cnt == 1) return (double)(p[0].y - p[0].x + p[0].y) / 2;
else
{
double res = 0;
res += (double)(p[0].y - slope(p[1], p[0]) * p[0].x + p[0].y) * slope(p[1], p[0]) / 2;
res += (double)(- slope(p[cnt - 1], p[cnt - 2]) * p[cnt - 1].x + p[cnt - 1].y - p[cnt - 1].x + p[cnt - 1].y) * (1 - slope(p[cnt - 1], p[cnt - 2])) / 2;
for(int i = 1; i < cnt - 1; ++ i)
res += (double)(- slope(p[i], p[i - 1]) * p[i].x + p[i].y - slope(p[i + 1], p[i]) * p[i].x + p[i].y) * (slope(p[i + 1], p[i]) - slope(p[i], p[i - 1])) / 2;
return res;
}
}
} nd[N + 1];
inline void addEdge(int u, int v, int x, int y)
{
nd[u].edg.push_back(edge(nd + v, x, y)); nd[v].edg.push_back(edge(nd + u, x, y));
}
struct record
{
node *u; int x, y;
inline record(node *_u, int _x, int _y)
{
u = _u; x = _x; y = _y;
}
};
inline void SPFA()
{
deque<record> que; que.clear(); que.push_back(record(nd + S, 0, 0)); nd[S].st.insert(point(0, 0));
for(; ! que.empty(); que.pop_front())
{
record cur = que.front();
if(! cur.u->check(point(cur.y - cur.x, cur.y))) continue;
for(auto edg : cur.u->edg) if(edg.v->insert(point(edg.y + cur.y - edg.x - cur.x, edg.y + cur.y))) que.push_back(record(edg.v, cur.x + edg.x, cur.y + edg.y));
}
}
}G;
int main()
{
#ifndef ONLINE_JUDGE
freopen("path.in", "r", stdin);
freopen("path.out", "w", stdout);
#endif
using namespace Zeonfai;
n = getInt(), m = getInt(), S = getInt(), T = getInt();
for(int i = 0; i < m; ++ i)
{
int u = getInt(), v = getInt(), x = getInt(), y = getInt();
G.addEdge(u, v, x, y);
}
G.SPFA();
printf("%.5lf", G.nd[T].getAnswer());
}
2016北京集训测试赛(九)Problem C: 狂飙突进的幻想乡的更多相关文章
- 2016北京集训测试赛(十七)Problem C: 数组
Solution 线段树好题. 我们考虑用last[i]表示\(i\)这个位置的颜色的上一个出现位置. 考虑以一个位置\(R\)为右端点的区间最远能向左延伸到什么位置: \(L = \max_{i \ ...
- 2016北京集训测试赛(十七)Problem B: 银河战舰
Solution 好题, 又是长链剖分2333 考虑怎么统计答案, 我场上的思路是统计以一个点作为结尾的最长上升链, 但这显然是很难处理的. 正解的方法是统计以每个点作为折弯点的最长上升链. 具体的内 ...
- 2016北京集训测试赛(十七)Problem A: crash的游戏
Solution 相当于要你计算这样一个式子: \[ \sum_{x = 0}^m \left( \begin{array}{} m \\ x \end{array} \right) \left( \ ...
- 2016北京集训测试赛(十六)Problem C: ball
Solution 这是一道好题. 考虑球体的体积是怎么计算的: 我们令\(f_k(r)\)表示\(x\)维单位球的体积, 则 \[ f_k(1) = \int_{-1}^1 f_{k - 1}(\sq ...
- 2016北京集训测试赛(十六)Problem B: river
Solution 这题实际上并不是构造题, 而是一道网络流. 我们考虑题目要求的一条路径应该是什么样子的: 它是一个环, 并且满足每个点有且仅有一条出边, 一条入边, 同时这两条边的权值还必须不一样. ...
- 2016北京集训测试赛(十六)Problem A: 任务安排
Solution 这道题告诉我们, 不能看着数据范围来推测正解的时间复杂度. 事实证明, 只要常数足够小, \(5 \times 10^6\)也是可以跑\(O(n \log n)\)算法的!!! 这道 ...
- BZOJ 4543 2016北京集训测试赛(二)Problem B: thr 既 长链剖分学习笔记
Solution 这题的解法很妙啊... 考虑这三个点可能的形态: 令它们的重心为距离到这三个点都相同的节点, 则其中两个点分别在重心的两棵子树中, 且到重心的距离相等; 第三个点可能在重心的一棵不同 ...
- 2016北京集训测试赛(十四)Problem B: 股神小D
Solution 正解是一个\(\log\)的link-cut tree. 将一条边拆成两个事件, 按照事件排序, link-cut tree维护联通块大小即可. link-cut tree维护子树大 ...
- 2016北京集训测试赛(十四)Problem A: 股神小L
Solution 考虑怎么卖最赚钱: 肯定是只卖不买啊(笑) 虽然说上面的想法很扯淡, 但它确实能给我们提供一种思路, 我们能不买就不买; 要买的时候就买最便宜的. 我们用一个优先队列来维护股票的价格 ...
随机推荐
- 【bzoj3339】Rmq Problem
[bzoj3339]Rmq Problem Description Input Output Sample Input 7 50 2 1 0 1 3 21 32 31 43 62 7 Sample ...
- 设计模式之第17章-备忘录模式(Java实现)
设计模式之第17章-备忘录模式(Java实现) 好男人就是我,我就是曾小贤.最近陈赫和张子萱事件闹得那是一个沸沸扬扬.想想曾经每年都有爱情公寓陪伴的我现如今过年没有了爱情公寓总是感觉缺少点什么.不知道 ...
- Spider_Man_6 の Scrapy(未完待续)
一:自我介绍 Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中.其最初是为了页面抓取 (更确切来说, 网络抓取 )所 ...
- var、let、const与JavaScript变量/常量的定义
早期的JavaScript中,声明变量只能使用var关键字定义变量,并没有定义常量的功能.通过var关键字定义的变量,其作用域只能函数级或是全局作用域,并没有块级作用域.ES6(ECMAScript ...
- easyui datagrid 学习 (一)
注意:当使用谷歌浏览器时!需要 设置style="overflow:hidden",这样则可以去掉滚动条!(该样式添加到layout上!) fit:属性 自动填父容器, borde ...
- IIS是怎么处理同时到来的多个请求的?
假设有一台服务器,它的IIS上部署有一个Web应用程序-S,可以通过浏览器或其他方式进行访问. 假设有A.B.C三台电脑同时访问网站S,IIS接收到3个HTTP请求,然后分别为三个请求 ...
- vue-cli 脚手架分析
Vue-cli 一.安装vue-cli 安装vue-cli的前提是你已经安装了npm,安装npm你可以直接下载node的安装包进行安装.你可以在命令行工具里输入npm -v 检测你是否安装了npm和 ...
- 第六篇:python基础_6 内置函数与常用模块(一)
本篇内容 内置函数 匿名函数 re模块 time模块 random模块 os模块 sys模块 json与pickle模块 shelve模块 一. 内置函数 1.定义 内置函数又被称为工厂函数. 2.常 ...
- JAVA与VB通过SOCKET通讯
JAVA与VB通过SOCKET通讯 在做项目的过程中,本来是想使用JAVA的comm.jar工具实现串口通讯,不知道怎么回事,总是取不到电脑的串口.所以,改为现在的这种模式:java通过socket给 ...
- BZOJ3295 [Cqoi2011]动态逆序对 【CDQ分治】
题目 对于序列A,它的逆序对数定义为满足i 输入格式 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数.以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次为 ...