Bzoj 3747: [POI2015]Kinoman 线段树

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[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。

HINT

 

Source

鸣谢Jcvb

题解:

线段树。。。

用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 }
原文地址:https://www.cnblogs.com/Var123/p/5315266.html