数据备份BZOJ1150
思路
题干在这:
BZOJ1150
我们注意到选取的一定是相邻的边,那我们先求出两两之间相隔的距离d[i]。可知如果我们选了d[i],那么我们就不能选d[i-1]和d[i+1]。我们每次找到一个最小的值d[i],并把d[i],d[i-1]和d[i+1]删去;我们又要保留选d[i-1]和d[i+1]的可能性,所以再在原位插进去值为d[i-1]+d[i+1]-d[i]的点。
我们用一个优先队列得到最小值,并用np和pp记录某个点下一个点和上一个点的位置,并且每次操作实时更新。
注意边界条件,如果选了边上的点,则该点边上的点一定不会被选,所以直接删去这两个点就好。
为了防止复杂的讨论,在两端插入值为inf的点,这两个点显然不会被选,简化了操作
ac代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<queue>
#define N 100010
#define inf 0x3f3f3f3f
using namespace std;
int locate[N] = { 0 };
struct point {
int val;
int self;
friend bool operator<(const point& a, const point& b) {
return a.val > b.val;
}
}distant[N];
int mark[N];
int np[N], pp[N];
priority_queue<point> solve;
int main() {
int n, k;
long long sum = 0;
cin >> n >> k;
for (int i = 1; i <= n; i++)
cin >> locate[i];
distant[0].val = inf;
distant[n].val = inf;
solve.push(distant[0]);
solve.push(distant[n]);
for (int i = 1; i < n; i++) {
distant[i].val = locate[i + 1] - locate[i];
np[i] = i + 1;
distant[i].self = i;
pp[i] = i - 1;
solve.push(distant[i]);
}
while (1) {
while (solve.size()&&mark[solve.top().self])
solve.pop();
if (k == 0 || solve.size() == 0) {
cout << sum;
return 0;
}
point mid = solve.top();
solve.pop();
sum += mid.val;
if (np[mid.self] == n) {
np[pp[pp[mid.self]]] = n;
mark[pp[mid.self]] = 1;
}
else if (pp[mid.self] == 0) {
pp[np[np[mid.self]]] = 0;
mark[np[mid.self]] = 1;
}
else {
mark[np[mid.self]] = 1;
mark[pp[mid.self]] = 1;
point insert;
insert.val = distant[np[mid.self]].val + distant[pp[mid.self]].val - mid.val;
insert.self = mid.self;
distant[insert.self].val = insert.val;
np[mid.self] = np[np[mid.self]];
pp[np[mid.self]] = mid.self;
pp[mid.self] = pp[pp[mid.self]];
np[pp[mid.self]] = mid.self;
solve.push(insert);
}
k--;
}
}
版权声明:本文为qq_45616764原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。