码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ3747: [POI2015]Kinoman

时间:2017-09-13 01:49:46      阅读:248      评论:0      收藏:0      [点我收藏+]

标签:efi   ble   删除   无法获得   turn   content   包含   pac   man   

3747: [POI2015]Kinoman

Time Limit: 60 Sec  Memory Limit: 128 MB
Submit: 991  Solved: 425
[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[n](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。

思路{

  和HH的项链树状数组做法的思想类似.

  有重复的颜色记录出$ Nxt [ i ] $为下一个和$ i $ 颜色相同的位置.

  那么从左往右扫区间右端点,相当于一个取$ Max $的操作.用线段树维护.

  考虑更改,删除当前点{

    删除区间[ i , Nxt [ i ] ] 贡献,

    新增区间 [ Nxt [ i ] ,Nxt [ i ] ] 贡献

  }

  用线段树搞就可以了.

}

#include<bits/stdc++.h>
#define il inline
#define RG register
#define ll long long
#define db double
#define N 1000010
using namespace std;
int w[N],f[N],n,m,last[N],nxt[N],fir[N];
namespace Tree{
  ll Max[N*4],lazy[N*4];
#define rs ((o<<1)|1)
#define ls (o<<1)
#define mid ((l+r)>>1)
  void up(int o){
    Max[o]=max(Max[rs],Max[ls]);
  }
  void down(int o){
    if(lazy[o]){
      Max[rs]+=lazy[o];lazy[rs]+=lazy[o];
      Max[ls]+=lazy[o];lazy[ls]+=lazy[o];
      lazy[o]=0;
    }
  }
  void Insert(int o,int l,int r,int L,int R,ll num){
    if(l!=r)down(o);
    if(l>=L&&r<=R){Max[o]+=num,lazy[o]+=num;return;}
    if(mid<L)Insert(rs,mid+1,r,L,R,num);
    else if(mid>=R)Insert(ls,l,mid,L,R,num);
    else Insert(rs,mid+1,r,mid+1,R,num),Insert(ls,l,mid,L,mid,num);
    up(o);
  }
  ll Query(int o,int l,int r,int L,int R){
    if(l!=r)down(o);
    if(l>=L&&r<=R)return Max[o];
    if(mid<L)return Query(rs,mid+1,r,L,R);
    else if(mid>=R)return Query(ls,l,mid,L,R);
    else return max(Query(rs,mid+1,r,L,R),Query(ls,l,mid,L,R));
  }
}
int main(){
  scanf("%d%d",&n,&m);for(int i=1;i<=n;++i)scanf("%d",&f[i]);
  for(int i=1;i<=m;++i)scanf("%d",&w[i]);
  for(int i=1;i<=n;++i){
    if(last[f[i]])nxt[last[f[i]]]=i;
    last[f[i]]=i;
  }
  memset(last,0,sizeof(last));
  for(int i=n;i;i--){
    if(last[f[i]])fir[last[f[i]]]=i;
    last[f[i]]=i;
  }
  for(int i=1;i<=n;++i)
    if(!fir[i]){
      if(nxt[i])Tree::Insert(1,1,n,i,nxt[i]-1,w[f[i]]);
      else Tree::Insert(1,1,n,i,n,w[f[i]]);
    }
  ll Ans(0);
  for(int i=1;i<=n;++i){
    Ans=max(Ans,Tree::Query(1,1,n,i,n));
    if(nxt[i]){
      Tree::Insert(1,1,n,i,nxt[i]-1,-w[f[i]]);
      if(nxt[nxt[i]])Tree::Insert(1,1,n,nxt[i],nxt[nxt[i]]-1,w[f[i]]);
      else Tree::Insert(1,1,n,nxt[i],n,w[f[i]]);
    }
    else Tree::Insert(1,1,n,i,n,-w[f[i]]);
  }cout<<Ans;
  return 0;
}

 

BZOJ3747: [POI2015]Kinoman

标签:efi   ble   删除   无法获得   turn   content   包含   pac   man   

原文地址:http://www.cnblogs.com/zzmmm/p/7512973.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!