ZOJ3724 Delivery(树状数组??)
题意:给你一个有向图,第一类边是从第i个点到第i+1个点的,还有多出来的m条二类边,是从u到v的,同样是有向的。然后你要处理询问,从u到v经过最多一次二类边的最短距离是多少。
题目我觉得是神题,然后看了网上的一些神解法,其中一个非常neatly,在此说下感想。
首先我们考虑的是(u<v)的所有询问,那么我们可以发现,这个时候所有二类边(u>v)的,是不可能用到的。然后我们想,从u到v的最短距离,就是利用u+1~v中的某个起点的二类边到达某个点k(u<k<=v),所以在计算的时候我们只需要知道这些边里能节省的距离的最小值就可以了。所以当我们把询问离线,我们优先处理的是u大v小的边,然后对于每天边,我们可以更新一下对应的节省了的距离的最小值,然后询问的时候就是两点间的距离+节省距离的最小值。
同样,在处理(u>v)的询问的时候,所有的二类边(u<v)也是不会用到的。然后在询问(v,u)的时候,我们也是要用到的所以在u之后为起点的边,以及以u为起点,终点在v前的边。但是这个时候询问就有点坑爹了,因为我们是从u到达u1,经过一条u1->v1的边,然后从v1到达v,区间顺序如下:(v1,v,u,u1),那么花费究竟什么时候最少呢?我们如何利用u1->v1这条边去更新呢?不难发现,我们实际上的距离其实就是 dis(u1,v1)+cost(u1,v1)-dis(v,u),所以在询问的时候u,v是不起作用的,相当于一个常数,我们需要的只是dis(u1,v1)+cost(u1,v1)最小,所以更新的时候只需要维护这个就好了。至此圆满结束。
值得注意的是bit数组的维护以及更新的顺序。
这道题叫我做我肯定做不会,但是这种离线的思想我觉得太重要了,很多看上去解决不了的数据结构归结起来就是没有合适的离线处理。
#pragma warning(disable:4996)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define ll long long
#define maxn 100000
#define maxm 200000
#define lowbit(k) k&(-k)
using namespace std; struct Node
{
int u,v;
ll d;
int idx; int kind;
bool operator < (const Node &b) const{
if (u == b.u){
if (v == b.v) return kind < b.kind;
else return v < b.v;
}
else return u > b.u;
}
}seg[maxm*2];
int top;
ll d[maxn + 50];
ll sd[maxn + 50];
ll ans[maxm + 50];
ll n, m; ll bit[maxn + 50]; void upd(int x, ll val){
while (x <= n){
bit[x] = min(bit[x], val);
x += lowbit(x);
}
} ll query(int x){
ll res = (1LL) << 60;
while (x){
res = min(res, bit[x]);
x -= lowbit(x);
}
return res;
} int main()
{
while (cin >> n >> m){
for (int i = 1; i <= n - 1; i++){
scanf("%lld", &d[i]);
}
sd[1] = 0;
for (int i = 1; i <= n - 1; i++){
sd[i + 1] = sd[i] + d[i];
}
int ui, vi; ll qi; top = 0;
for (int i = 0; i < m; i++){
scanf("%d%d%lld", &seg[top].u, &seg[top].v, &seg[top].d);
seg[top].idx = i; seg[top].kind = 0;
top++;
}
int q; cin >> q;
for (int i = 0; i < q; i++){
scanf("%d%d", &seg[top].u, &seg[top].v);
seg[top].kind = 1; seg[top].idx = i; top++;
}
sort(seg, seg + top);
memset(ans, 0, sizeof(ans));
memset(bit, 0, sizeof(bit));
for (int i = 0; i < top; i++){
if (seg[i].kind == 0 && seg[i].u < seg[i].v){
upd(seg[i].v, seg[i].d - (sd[seg[i].v] - sd[seg[i].u])); // 节省距离的相反数
}
if (seg[i].kind == 1 && seg[i].u < seg[i].v){
ans[seg[i].idx] = query(seg[i].v) + sd[seg[i].v] - sd[seg[i].u];
}
}
for (int i = 1; i <= n; i++) bit[i] = (1LL << 60);
for (int i = 0; i < top; i++){
if (seg[i].kind == 0 && seg[i].u>seg[i].v){
upd(seg[i].v, seg[i].d + sd[seg[i].u] - sd[seg[i].v]);
}
if (seg[i].kind == 1 && seg[i].u>seg[i].v){
ans[seg[i].idx] = query(seg[i].v) - (sd[seg[i].u] - sd[seg[i].v]);
}
}
for (int i = 0; i < q; i++){
printf("%lld\n", ans[i]);
}
}
return 0;
}
ZOJ3724 Delivery(树状数组??)的更多相关文章
- ZOJ 3724 Delivery 树状数组好题
虽然看起来是求最短路,但因为条件的限制,可以转化为区间求最小值. 对于一条small path [a, b],假设它的长度是len,它对区间[a, b]的影响就是:len-( sum[b]-sum[a ...
- BZOJ 1103: [POI2007]大都市meg [DFS序 树状数组]
1103: [POI2007]大都市meg Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2221 Solved: 1179[Submit][Sta ...
- bzoj1878--离线+树状数组
这题在线做很麻烦,所以我们选择离线. 首先预处理出数组next[i]表示i这个位置的颜色下一次出现的位置. 然后对与每种颜色第一次出现的位置x,将a[x]++. 将每个询问按左端点排序,再从左往右扫, ...
- codeforces 597C C. Subsequences(dp+树状数组)
题目链接: C. Subsequences time limit per test 1 second memory limit per test 256 megabytes input standar ...
- BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2545 Solved: 1419[Submit][Sta ...
- BZOJ 3529: [Sdoi2014]数表 [莫比乌斯反演 树状数组]
3529: [Sdoi2014]数表 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1399 Solved: 694[Submit][Status] ...
- BZOJ 3289: Mato的文件管理[莫队算法 树状数组]
3289: Mato的文件管理 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 2399 Solved: 988[Submit][Status][Di ...
- 【Codeforces163E】e-Government AC自动机fail树 + DFS序 + 树状数组
E. e-Government time limit per test:1 second memory limit per test:256 megabytes input:standard inpu ...
- 【BZOJ-3881】Divljak AC自动机fail树 + 树链剖分+ 树状数组 + DFS序
3881: [Coci2015]Divljak Time Limit: 20 Sec Memory Limit: 768 MBSubmit: 508 Solved: 158[Submit][Sta ...
随机推荐
- opengl基础学习专题 (二) 点直线和多边形
题外话 随着学习的增长,越来越觉得自己很水.关于上一篇博文中推荐用一个 学习opengl的 基于VS2015的 simplec框架.存在 一些问题. 1.这个框架基于VS 的Debug 模式下,没有考 ...
- DIV指令一般用法
本文最初发表于2015-8-14,是由别的地方迁移过来的 (本文所讲为无符号运算) DIV指令是8086汇编中的除法运算指令,它的结果不是浮点数,而是两个整数:商和余数. 我们来看王爽老师是怎么讲的: ...
- iOS学习之C语言内存管理
一.存储区划分 按照地址从高到低的顺序:栈区,堆区,静态区,常量区,代码区 1.栈区:局部变量的存储区域 局部变量基本都在函数.循环.分支中定义 栈区的内存空 ...
- Linux 文件与目录
文件描述符 在内核中,所有打开的文件都使用文件描述符(一个非负整数)标记.文件描述符的变化范围是0~OPEN_MAX – 1.早期的unix系统中,每个进程最多可以同时打开20个文件,就是说文件描述符 ...
- 主要从架构上来做优化,负载均衡、CDN、静态化、数据库的水平切割和纵向切割、读写分离、分布式缓存着手
语言知识一种工具,甚至技术本身也只是一种工具,本身并不值钱,关键在于用于何种行业,产生了什么价值. 但从语言来看,我个人更喜欢php,然后是C#,然后是java从框架而言,先是java,然后C#,再次 ...
- Oracle之sql追踪
select * from v$sqlarea t where t.sql_text like '%_070%' order by t.LAST_ACTIVE_TIME desc SELECT * F ...
- 如何在github上fork一个项目来贡献代码以及同步原作者的修改
[-] 如何贡献自己的力量 如何让自己的项目与原作者的项目保持同步 作为一个IT人,通过github进行学习是最快的成长手 段.我们可以浏览别人的优秀代码.但只看不动手还是成长得很慢,因此为别人贡献代 ...
- linux free 命令
命 令: free 功能说明:显示内存状态. 语 法: free [-bkmotV][-s <间隔秒数>] 补充说明:free指令会显示内存的使用情况,包括实体内存,虚拟的交换文件内存,共 ...
- 升级ubuntu内核
ubuntu12.04内核为 linux-image-3.5.0-23-generic 要升级为 linux-image-3.2.0-57-generic 使用apt-get install linu ...
- 使用javac命令编译java文件。
今天想学习一下web services的知识,在网上找了一个教程,里面写了一个web services客户端调用,在cmd下执行的,但是没有给出用javac编译的细节.所以自己就借着这个机会学了一下: ...