题意:给你一个有向图,第一类边是从第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(树状数组??)的更多相关文章

  1. ZOJ 3724 Delivery 树状数组好题

    虽然看起来是求最短路,但因为条件的限制,可以转化为区间求最小值. 对于一条small path [a, b],假设它的长度是len,它对区间[a, b]的影响就是:len-( sum[b]-sum[a ...

  2. BZOJ 1103: [POI2007]大都市meg [DFS序 树状数组]

    1103: [POI2007]大都市meg Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2221  Solved: 1179[Submit][Sta ...

  3. bzoj1878--离线+树状数组

    这题在线做很麻烦,所以我们选择离线. 首先预处理出数组next[i]表示i这个位置的颜色下一次出现的位置. 然后对与每种颜色第一次出现的位置x,将a[x]++. 将每个询问按左端点排序,再从左往右扫, ...

  4. codeforces 597C C. Subsequences(dp+树状数组)

    题目链接: C. Subsequences time limit per test 1 second memory limit per test 256 megabytes input standar ...

  5. BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2545  Solved: 1419[Submit][Sta ...

  6. BZOJ 3529: [Sdoi2014]数表 [莫比乌斯反演 树状数组]

    3529: [Sdoi2014]数表 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1399  Solved: 694[Submit][Status] ...

  7. BZOJ 3289: Mato的文件管理[莫队算法 树状数组]

    3289: Mato的文件管理 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 2399  Solved: 988[Submit][Status][Di ...

  8. 【Codeforces163E】e-Government AC自动机fail树 + DFS序 + 树状数组

    E. e-Government time limit per test:1 second memory limit per test:256 megabytes input:standard inpu ...

  9. 【BZOJ-3881】Divljak AC自动机fail树 + 树链剖分+ 树状数组 + DFS序

    3881: [Coci2015]Divljak Time Limit: 20 Sec  Memory Limit: 768 MBSubmit: 508  Solved: 158[Submit][Sta ...

随机推荐

  1. Unicode字符以16进制表示

    int(x [,base ])         将x转换为一个整数 long(x [,base ])        将x转换为一个长整数 float(x )               将x转换到一个 ...

  2. 解决matplotlib中文乱码问题(Windows)

    1.修改matplotlibrc文件 进入Python安装目录下的Lib\site-packages\matplotlib\mpl-data目录,打开matplotlibrc文件,删除font.fam ...

  3. node.js 使用 UglifyJS2 高效率压缩 javascript 文件

    UglifyJS2 这个工具使用很长时间了,但之前都是在 gulp 自动构建 时用到了 UglifyJS 算法进行压缩. 最近玩了一下 UglifyJS2 ,做了一个 在线压缩javascript工具 ...

  4. linux 命令 more

    more命令: 从前往后读取文件,启动时加载整个文件,让整个文件的内容从上到下显示在屏幕上. 可以逐页读取,空格(space):下一页,b键(back):上一页,而且还有搜索字符串的功能. more ...

  5. Linux/Android 系统怎么修改mac地址

    使用 busybox ifconfig eth0 hw ether AA:BB:CC:DD:EE 可以修改, 但是每次重启都会改回原来的. 所以要修改 /etc/init.mini210.sh (可能 ...

  6. 关于asp.net和iis的进程/线程问题,假如网站有1000个人访问,会产生多少个进程/线程啊

    详解 ASP.NET异步   超好的文章

  7. Xcode全局断点

    1.将导航器视图切换到断点导航器视图下,也可以用快捷键Command+7一步搞定,键盘是window风格的用户Command键是win键(有微软logo),然后点击左下角的+号,选择Add Symbo ...

  8. Swift计算文本宽高

    iOS 8 开始可以配合 AutoLayout 自动估算文本的高度,但是当 Cell 比较复杂的时候,还会需要手动去计算.首先声明一个样式 var TextStyle : [String : NSOb ...

  9. IOS内存管理「1」- 引用计数

  10. mysql几个命令

    1.格式化输出 select * from mysql.user\G 2.显示版本 show version() 3.显示引擎 show engines mysql> show engines; ...