题目大意:给出电影院的放映电影顺序,一个电影只有看过一次的时候会获得电影的权值。没看过或者看两次或以上都不能获得权值。问看连续区间的电影能够获得的最大权值是多少。
思路:利用线段树维护前缀和。将出现第一次的地方的权值加上那部电影的权值,第二次出现的时候权值减去那部电影的权值。枚举起点,先更新答案,然后在当前节点减去权值的二倍,然后再在下一次出现的地方加上权值(我感觉我没说明白,总之看代码吧。。。
CODE:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 1000010
using namespace std;
#define LEFT (pos << 1)
#define RIGHT (pos << 1|1)
struct SegTree{
long long _max,c;
}tree[MAX << 2];
int total,cnt;
int src[MAX],value[MAX];
int first[MAX],last[MAX],next[MAX];
inline void PushDown(int pos)
{
if(tree[pos].c) {
tree[LEFT]._max += tree[pos].c;
tree[RIGHT]._max += tree[pos].c;
tree[LEFT].c += tree[pos].c;
tree[RIGHT].c += tree[pos].c;
tree[pos].c = 0;
}
}
inline void Modify(int l,int r,int x,int y,int c,int pos)
{
if(l == x && y == r) {
tree[pos]._max += c;
tree[pos].c += c;
return ;
}
PushDown(pos);
int mid = (l + r) >> 1;
if(y <= mid) Modify(l,mid,x,y,c,LEFT);
else if(x > mid) Modify(mid + 1,r,x,y,c,RIGHT);
else {
Modify(l,mid,x,mid,c,LEFT);
Modify(mid + 1,r,mid + 1,y,c,RIGHT);
}
tree[pos]._max = max(tree[LEFT]._max,tree[RIGHT]._max);
}
inline long long Ask(int l,int r,int x,int y,int pos)
{
if(l == x && y == r)
return tree[pos]._max;
PushDown(pos);
int mid = (l + r) >> 1;
if(y <= mid) return Ask(l,mid,x,y,LEFT);
if(x > mid) return Ask(mid + 1,r,x,y,RIGHT);
long long left = Ask(l,mid,x,mid,LEFT);
long long right = Ask(mid + 1,r,mid + 1,y,RIGHT);
return max(left,right);
}
int main()
{
cin >> total >> cnt;
for(int i = 0; i < MAX; ++i) next[i] = total + 1;
for(int i = 1; i <= total; ++i) {
scanf("%d",&src[i]);
if(!first[src[i]]) {
first[src[i]] = i;
last[src[i]] = i;
}
else {
next[last[src[i]]] = i;
last[src[i]] = i;
}
}
for(int i = 1; i <= cnt; ++i)
scanf("%d",&value[i]);
for(int i = 1; i <= cnt; ++i)
if(first[i]) {
Modify(1,total + 1,first[i],total + 1,value[i],1);
Modify(1,total + 1,next[first[i]],total + 1,-value[i],1);
}
long long ans = 0;
for(int i = 1; i <= total; ++i) {
ans = max(ans,Ask(1,total,i,total,1));
Modify(1,total + 1,i,total + 1,-value[src[i]],1);
Modify(1,total + 1,next[i],total + 1,value[src[i]] << 1,1);
Modify(1,total + 1,next[next[i]],total + 1,-value[src[i]],1);
}
cout << ans << endl;
return 0;
}