Bzoj 3747: [POI2015]Kinoman 线段树
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[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
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。
样例解释:
观看第2,3,4,5,6,7天内放映的电影,其中看且仅看过一次的电影的编号为2,3,4。
HINT
Source
题解:
线段树。。。
用last[]记录每个位置的电影的上一个位置。
然后从头到尾依次遍历,每次把 (当前位置的电影的上一个位置,当前位置] 这个区间加上当前电影的好看值。然后把 (当前位置的电影的上上一个位置,当前位置的电影的上一个位置] 这个区间减去当前电影的好看值。每次求区间最大值即可。
这个用线段树维护即可。。。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define INF 1e9 4 #define LL long long 5 struct node 6 { 7 int left,right; 8 LL tag,mx; 9 }tree[4000050]; 10 int f[1000010],w[1000010],last[1000010],pre[1000010]; 11 int read() 12 { 13 int s=0,fh=1;char ch=getchar(); 14 while(ch<'0'||ch>'9'){if(ch=='-')fh=-1;ch=getchar();} 15 while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();} 16 return s*fh; 17 } 18 void Build(int k,int l,int r) 19 { 20 tree[k].left=l;tree[k].right=r;tree[k].tag=0;tree[k].mx=0; 21 if(l==r)return; 22 int mid=(l+r)/2; 23 Build(k*2,l,mid);Build(k*2+1,mid+1,r); 24 } 25 void Pushup(int k) 26 { 27 tree[k].mx=max(tree[k*2].mx,tree[k*2+1].mx); 28 } 29 void Pushdown(int k) 30 { 31 if(tree[k].tag!=0) 32 { 33 tree[k*2].tag+=tree[k].tag; 34 tree[k*2+1].tag+=tree[k].tag; 35 tree[k*2].mx+=tree[k].tag; 36 tree[k*2+1].mx+=tree[k].tag; 37 tree[k].tag=0; 38 } 39 } 40 void Add(int k,int l,int r,int add) 41 { 42 if(l<=tree[k].left&&tree[k].right<=r) 43 { 44 tree[k].tag+=(LL)add; 45 tree[k].mx+=(LL)add; 46 return; 47 } 48 Pushdown(k); 49 int mid=(tree[k].left+tree[k].right)/2; 50 if(r<=mid)Add(k*2,l,r,add); 51 else if(l>mid)Add(k*2+1,l,r,add); 52 else {Add(k*2,l,mid,add);Add(k*2+1,mid+1,r,add);} 53 Pushup(k); 54 } 55 int main() 56 { 57 int n,m,i; 58 LL ans; 59 n=read();m=read(); 60 for(i=1;i<=n;i++)f[i]=read(); 61 for(i=1;i<=m;i++)w[i]=read(); 62 memset(last,0,sizeof(last)); 63 memset(pre,0,sizeof(pre)); 64 for(i=1;i<=n;i++) 65 { 66 last[i]=pre[f[i]]; 67 pre[f[i]]=i; 68 } 69 Build(1,1,n); 70 ans=-INF; 71 for(i=1;i<=n;i++) 72 { 73 Add(1,last[i]+1,i,w[f[i]]); 74 if(last[i]!=0) 75 { 76 Add(1,last[last[i]]+1,last[i],-w[f[i]]); 77 } 78 ans=max(ans,tree[1].mx); 79 } 80 printf("%lld",ans); 81 return 0; 82 }