P2672 推销员 - 线段树 - 离线处理
注意这X家不一定连续,并且输入中给定的就是第i家到入口的距离
先想只有一个的情况,扫一遍,找到其中最大的那个(路径要乘上2)
两个的呢?不大好想,不如想想n个的时候,情况最简单,那么从n到n-1的转移也很简单
考虑把过程反过来,一个个删点,每次删使得答案变化最小的点
现在问题是 快速找出区间内对答案变化贡献最小的一点及其位置,与区间目前最右端点某些信息比较后就可以得到答案
要维护这么多信息,还是区间上的,要么线段树要么平衡树
用线段树维护!
注意维护目前最右边的点的位置r_pos以及下次最右边的位置nxt
这个nxt更新要及时,但是又不能更新太多次
一开始我写了个非常慢的更新= =
这样子的:
int nxt = r_pos - 1;
while(vis[nxt]) nxt--;
这样每次循环的时候都会重新找一次nxt,十分的慢,不如把nxt定义在循环外面及时维护
注意删除右端点的时候,让现在nxt成为现在右端点,那么这个时候nxt应该也要发生更新
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cmath>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 100000 + 10;
const int INF = 1 << 30;
typedef long long ll;
int n,ans,now;
int a[MAXN],sum_path[MAXN],sum_a[MAXN],path[MAXN],pla[MAXN],vis[MAXN];
// segment tree
struct segment{
int mi, pos;
}tr[MAXN * 4];
void update(int w) {
int le = w * 2, ri = w * 2 + 1;
if(tr[le].mi < tr[ri].mi) {
tr[w].mi = tr[le].mi;
tr[w].pos = tr[le].pos;
} else {
tr[w].mi = tr[ri].mi;
tr[w].pos = tr[ri].pos;
}
}
void build(int w, int l, int r) {
if(l == r) {
tr[w].mi = a[l];
tr[w].pos = l;
return;
}
int le = w * 2, ri = w * 2 + 1, mid = (l + r) / 2;
build(le, l, mid);
build(ri, mid+1, r);
update(w);
}
void del(int w, int l, int r, int pos) {
if(l == r) {
tr[w].mi = INF;
return;
}
int le = w * 2, ri = w * 2 + 1, mid = (l + r) / 2;
if(pos <= mid)
del(le, l, mid, pos);
else
del(ri, mid+1, r, pos);
update(w);
}
int main() {
scanf("%d", &n);
for(int i=1; i<=n; i++) {
scanf("%d", &path[i]);
}
for(int i=1; i<=n; i++) {
scanf("%d", &a[i]);
}
build(1, 1, n);
for(int i=1; i<=n; i++) {
now += a[i];
}
now += path[n] * 2;
pla[n] = now;
int r_pos = n;
del(1, 1, n, n);
int nxt = n - 1;
for(int i=n-1; i; i--) {
int pos = tr[1].pos;
int dis = (path[r_pos] - path[nxt]) * 2;
if(a[pos] > dis + a[r_pos]) {
now -= dis + a[r_pos];
r_pos = nxt;
del(1, 1, n, r_pos);
vis[r_pos] = 1;
} else {
now -= a[pos];
vis[pos] = 1;
del(1, 1, n, pos);
}
while(vis[nxt]) nxt--;
pla[i] = now;
}
for(int i=1; i<=n; i++) {
printf("%d\n", pla[i]);
}
return 0;
}