您的位置:首页 > 其它

Bzoj 3747: [POI2015]Kinoman 线段树

2016-03-24 13:59 639 查看

3747: [POI2015]Kinoman

Time Limit: 60 Sec Memory Limit: 128 MB
Submit: 553 Solved: 222
[Submit][Status][Discuss]

Description

共有m部电影,编号为1~m,第i部电影的好看值为w[i]。
在n天之中(从1~n编号)每天会放映一部电影,第i天放映的是第f[i]部。
你可以选择l,r(1<=l<=r<=n),并观看第l,l+1,…,r天内所有的电影。如果同一部电影你观看多于一次,你会感到无聊,于是无法获得这部电影的好看值。所以你希望最大化观看且仅观看过一次的电影的好看值的总和。

Input

第一行两个整数n,m(1<=m<=n<=1000000)。
第二行包含n个整数f[1],f[2],…,f
(1<=f[i]<=m)。
第三行包含m个整数w[1],w[2],…,w[m](1<=w[j]<=1000000)。

Output

输出观看且仅观看过一次的电影的好看值的总和的最大值。

Sample Input

9 4

2 3 1 1 4 1 2 4 1

5 3 6 6

Sample Output

15

样例解释:

观看第2,3,4,5,6,7天内放映的电影,其中看且仅看过一次的电影的编号为2,3,4。

HINT

Source

鸣谢Jcvb

题解:

线段树。。。

用last[]记录每个位置的电影的上一个位置。

然后从头到尾依次遍历,每次把 (当前位置的电影的上一个位置,当前位置] 这个区间加上当前电影的好看值。然后把 (当前位置的电影的上上一个位置,当前位置的电影的上一个位置] 这个区间减去当前电影的好看值。每次求区间最大值即可。

这个用线段树维护即可。。。

#include<bits/stdc++.h>
using namespace std;
#define INF 1e9
#define LL long long
struct node
{
int left,right;
LL tag,mx;
}tree[4000050];
int f[1000010],w[1000010],last[1000010],pre[1000010];
int read()
{
int s=0,fh=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')fh=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();}
return s*fh;
}
void Build(int k,int l,int r)
{
tree[k].left=l;tree[k].right=r;tree[k].tag=0;tree[k].mx=0;
if(l==r)return;
int mid=(l+r)/2;
Build(k*2,l,mid);Build(k*2+1,mid+1,r);
}
void Pushup(int k)
{
tree[k].mx=max(tree[k*2].mx,tree[k*2+1].mx);
}
void Pushdown(int k)
{
if(tree[k].tag!=0)
{
tree[k*2].tag+=tree[k].tag;
tree[k*2+1].tag+=tree[k].tag;
tree[k*2].mx+=tree[k].tag;
tree[k*2+1].mx+=tree[k].tag;
tree[k].tag=0;
}
}
void Add(int k,int l,int r,int add)
{
if(l<=tree[k].left&&tree[k].right<=r)
{
tree[k].tag+=(LL)add;
tree[k].mx+=(LL)add;
return;
}
Pushdown(k);
int mid=(tree[k].left+tree[k].right)/2;
if(r<=mid)Add(k*2,l,r,add);
else if(l>mid)Add(k*2+1,l,r,add);
else {Add(k*2,l,mid,add);Add(k*2+1,mid+1,r,add);}
Pushup(k);
}
int main()
{
int n,m,i;
LL ans;
n=read();m=read();
for(i=1;i<=n;i++)f[i]=read();
for(i=1;i<=m;i++)w[i]=read();
memset(last,0,sizeof(last));
memset(pre,0,sizeof(pre));
for(i=1;i<=n;i++)
{
last[i]=pre[f[i]];
pre[f[i]]=i;
}
Build(1,1,n);
ans=-INF;
for(i=1;i<=n;i++)
{
Add(1,last[i]+1,i,w[f[i]]);
if(last[i]!=0)
{
Add(1,last[last[i]]+1,last[i],-w[f[i]]);
}
ans=max(ans,tree[1].mx);
}
printf("%lld",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: