Description
给有m部电影,每一部都有一个好看值w。
在n天里面,每一天都会放一部电影,其中第i天放的是第f[i]部电影,
现在,你可以任意选择一个区间[l,r],然后观看第l天到第r天内所有的电影。但是,如果同一部电影你观看了多于一次,你就无法获得这部电影的好看值。问最大好看值总和。
Input
第一行两个整数n,m,表示点数和操作数。
第二行包含n个整数,表示f[1],f[2]…f[n]。
第三行包含m个整数,表示w[1],w[2]…w[n]。
Output
输出最大好看值总和。
Hint
对于30%的数据,n,m<=1000.
对于100%的数据,n,m<=100000,1<=f[i]<=m,1<=w[i]<=1000000
Source
BY BPM
Solution
对于每个电影记录下一次出现的位置,枚举l的位置并线段树动态修改。第一次出现的我们计为+w,第二次的-w,第三次的移动一下即可
Code
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <queue>
#include <vector>
#include <algorithm>
#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)
#define drp(i, st, ed) for (int i = st; i >= ed; i -= 1)
#define erg(i, st) for (int i = ls[st]; i; i = e[i].next)
#define fill(x, t) memset(x, t, sizeof(x))
#define max(x, y) (x)>(y)?(x):(y)
#define min(x, y) (x)<(y)?(x):(y)
#define ll long long
#define db double
#define INF 0x3f3f3f3f
#define N 100201
struct treeNode{int l, r; ll mx, tag;}t[N << 2 | 1];
ll w[N], f[N], ls[N], next[N];
inline ll read(){
ll x=0,v=1; char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')v=-1; ch=getchar();}
while (ch<='9'&&ch>='0'){x=x*10+ch-'0'; ch=getchar();}
return x*v;
}
inline void pushDown(int now, int l, int r){
if (!t[now].tag){return ;}
t[now << 1].tag += t[now].tag;
t[now << 1].mx += t[now].tag;
t[now << 1 | 1].tag += t[now].tag;
t[now << 1 | 1].mx += t[now].tag;
t[now].tag = 0;
}
inline ll query(int now, int l, int r){
if (t[now].l == l && t[now].r == r){
return t[now].mx;
}
pushDown(now, l, r);
int mid = (t[now].l + t[now].r) >> 1;
if (r <= mid){
return query(now << 1, l, r);
}else if (l > mid){
return query(now << 1 | 1, l, r);
}else{
return max(query(now << 1, l, mid), query(now << 1 | 1, mid + 1, r));
}
}
inline void modify(int now, int l, int r, ll v){
if (t[now].l == l && t[now].r == r){
t[now].tag += v;
t[now].mx += v;
return ;
}
pushDown(now, l, r);
int mid = (t[now].l + t[now].r) >> 1;
if (r <= mid){
modify(now << 1, l, r, v);
}else if (l > mid){
modify(now << 1 | 1, l, r, v);
}else{
modify(now << 1, l, mid, v);
modify(now << 1 | 1, mid + 1, r, v);
}
t[now].mx = max(t[now << 1].mx, t[now << 1 | 1].mx);
}
inline void build(int now, int l, int r){
t[now] = (treeNode){l, r, 0};
if (l == r){return ;}
int mid = (l + r) >> 1;
build(now << 1, l, mid);
build(now << 1 | 1, mid + 1, r);
t[now].mx = max(t[now << 1].mx, t[now << 1 | 1].mx);
}
int main(void){
int n = read();
int m = read();
rep(i, 1, n){f[i] = read();}
rep(i, 1, m){w[i] = read();}
rep(i, 1, n){next[i] = n;}
drp(i, n, 1){
next[i] = ls[f[i]];
ls[f[i]] = i;
}
build(1, 1, n);
rep(i, 1, m){
if (ls[i]){
if (next[ls[i]]){
modify(1, ls[i], next[ls[i]] - 1, w[i]);
}else{
modify(1, ls[i], n, w[i]);
}
}
}
ll ans = 0;
rep(i, 1, n){
ans = max(ans, query(1, i, n));
if (next[i]){
modify(1, i, next[i] - 1, -w[f[i]]);
if (next[next[i]]){
modify(1, next[i], next[next[i]] - 1, w[f[i]]);
}else{
modify(1, next[i], n, w[f[i]]);
}
}else{
modify(1, i, n, -w[f[i]]);
}
}
printf("%lld\n", ans);
return 0;
}

本文介绍了一个基于线段树数据结构的算法,用于解决在有限天数内观看一系列重复播放的电影,以最大化总好看值的问题。通过记录每部电影首次出现的位置,并利用线段树动态维护观看区间,实现了高效求解。
2万+

被折叠的 条评论
为什么被折叠?



