老司机破阵
Time Limit: 4500/1500MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)Submit Status
老司机的女朋友被坏人抓起来了,护女票心切的老司机心急火燎的赶到坏人藏匿女票的地点想要救出她,但是老司机的神通广大坏人们早有耳闻,等老司机赶到时已经有一个法阵摆在他的面前阻挡着他。
法阵是一条直线上的n个法力元件构成的,老司机每次可以将一个法力元件击碎,法阵的能量就是所有 连贯的元件能量和的最大值 。
老司机非常的自信,他有一套自己的破除法阵的方案(
老司机希望能实时的关注着法阵的能量,一旦能量允许,他就破阵而入,救出女票。
忙着破阵的老司机自然没有功夫去计算他每步操作之后法阵的能量,他只能将此重任交与在座的各位大侠,请大家助他一臂之力。
Input
第一行n (1 ≤ n ≤ 100,000),为法力元件数量第二行有n个数,为每个法力元件所含有的能量ei(0 ≤ ei ≤ 1e9)
第三行有n个数,为老司机击破法力元件的顺序
Output
输出n行,为老司机每次击破法力元件后法阵的能量。Sample input and output
Sample Input Sample Output5
1 2 3 4 5
4 2 3 5 1
6
5
5
1
0
8
5 5 4 4 6 6 5 5
5 2 8 7 1 3 4 6
18
16
11
8
8
6
6
0
Hint
titleSource
2017 UESTC Training for Data Structures
My Solution
优先队列+双端链表
cf原题,直接贴的以前的代码
反向做,按着反的顺序把元素一个一个的添加进去,用priority_queue 维护当前最值,
用双向链表维护当前区间的状态,L[i]表示以i为端点的区间的区间左端点,
R[i]表示以i为区间端点的右端点。
对于每个点 j, 当只R[i + 1] != 0 时, 右边有区间,可以把两个链表合并成一个,
R[i] = R[i + 1], L[i] = i;
当只L[i - 1] != 0 时, 左边有区间,可以把两个链表合并成一个,
R[L[i - 1]] = i, R[i] = i, L[i] = L[i - 1]
当两边都有区间时,先合并一边,再合并另一边最后得到的区间是 [ L[i - 1], R[i + 1] ];
然后根据合并来的区间得到新的区间和,push到priority_queue里,这个和必定比原来分开的子区间大,
所以原来的子区间和就留在pq里不用管了。最多维护n个元素。
区间和用 map<pair<int, int>, LL> mp,来维护, mp[ii(i, i)] = a[per[i]];,
然后 mp[ii(l, r)]就用来维护新的区间的和,然后push到pq里。
复杂度 O(nlogn)
#include <iostream>
#include <cstdio>
#include <queue>
#include <map>
#include <cstring>
using namespace std;
typedef long long LL;
typedef pair<int, int> ii;
const int maxn = 1e5 + 8;
priority_queue<LL> pq;
map<ii, LL> mp;
LL a[maxn], per[maxn], L[maxn], R[maxn], ans[maxn];
int main()
{
#ifdef LOCAL
freopen("k.txt", "r", stdin);
//freopen("k.out", "w", stdout);
int T = 3;
while(T--){
#endif // LOCAL
//ios::sync_with_stdio(false); cin.tie(0);
LL n, l, r, sum;
//cin >> n;
scanf("%lld", &n);
for(int i = 1; i <= n; i++){
//cin >> a[i];
scanf("%lld", &a[i]);
}
for(int i = 1; i <= n; i++){
//cin >> per[i];
scanf("%lld", &per[i]);
}
for(int i = n; i > 0; i--){
if(i == n){
L[per[n]] = per[n];
R[per[n]] = per[n];
mp[ii(per[n], per[n])] = a[per[n]];
pq.push(a[per[n]]);
ans[n] = 0;
}
else{
ans[i] = pq.top();
sum = a[per[i]];
l = per[i], r = per[i];
L[l] = l, R[l] = l;
if(L[per[i]+1] != 0){
L[per[i]] = per[i];
R[per[i]] = R[per[i]+1];
L[R[per[i]+1]] = per[i];
r = R[per[i]];
sum += mp[ii(per[i]+1, r)];
}
if(R[per[i]-1] != 0){
if(R[per[i]] != 0){
R[L[per[i]-1]] = R[per[i]];
L[R[per[i]]] = L[per[i]-1];
l = L[per[i]-1];
sum += mp[ii(l, per[i]-1)];
}
else{
R[L[per[i]-1]] = per[i];
R[per[i]] = per[i];
L[per[i]] = L[per[i]-1];
l = L[per[i]-1];
sum += mp[ii(l, per[i]-1)];
}
}
mp[ii(l, r)] = sum;
pq.push(sum);
}
}
for(int i = 1; i <= n; i++){
//cout << ans[i] << "\n";
printf("%lld\n", ans[i]);
}
#ifdef LOCAL
memset(L, 0, sizeof L);
memset(R, 0, sizeof R);
mp.clear();
while(!pq.empty()) pq.pop();
cout << endl;
}
#endif // LOCAL
return 0;
}
Thank you!
------from ProLights