Bzoj 3747: [POI2015]Kinoman 线段树
2016-03-24 13:59
639 查看
3747: [POI2015]Kinoman
Time Limit: 60 Sec Memory Limit: 128 MBSubmit: 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 42 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; }
相关文章推荐
- mybatis foreach标签的解释 与常用之处
- ftp以及smb的配置
- [老老实实学WCF] 第五篇 再探通信--ClientBase
- Search gold(dp)
- Linux 第五章 学习笔记
- Android之screenOrientation和configChanges使用和注意事项
- ubuntu下qt5提示can not find -lGL
- Java HashMap工作原理及实现
- Java 数据结构 HashMap
- Java,break与continue区别(二)
- 什么是Memcache
- 数据库事务隔离级别是怎么回事?
- Java HashMap工作原理及实现
- Linux启动新进程的几种方法及比较
- CentOS 6.4下Squid代理服务器的安装与配置
- Lua和C++交互详细总结
- C#连接SQL SERVER数据库的详细步骤!
- Java组合与继承生成的类中构造函数的执行顺序
- [老老实实学WCF] 第四篇 初探通信--ChannelFactory
- 如何使用微信JS-SDK实际分享功能