首页 > 代码库 > 【BZOJ 3747】 3747: [POI2015]Kinoman (线段树)

【BZOJ 3747】 3747: [POI2015]Kinoman (线段树)

3747: [POI2015]Kinoman

Time Limit: 60 Sec  Memory Limit: 128 MB
Submit: 830  Solved: 338

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

 

 

【分析】

  这题应该挺经典。?

  就是先弄一个next,然后每次求以i结尾的最大值。

  i的值为w,next[i]的值为-w,更前面的next的值为0,线段树维护这个,(好像树状数组也是可以的),然后就好了。

 

技术分享
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 #define Maxn 1000010
 8 #define LL long long
 9 
10 // int mymax(int x,int y) {return x>y?x:y;}
11 LL mymax(LL x,LL y) {return x>y?x:y;}
12 
13 int a[Maxn],w[Maxn],f[Maxn],ft[Maxn],nt[Maxn];
14 
15 struct node
16 {
17     int l,r,lc,rc;
18     LL mx,lazy;
19 }tr[Maxn*2];
20 
21 int tot=0;
22 int build(int l,int r)
23 {
24     int x=++tot;
25     tr[x].l=l;tr[x].r=r;
26     tr[x].lazy=tr[x].mx=0;
27     if(l<r)
28     {
29         int mid=(l+r)>>1;
30         tr[x].lc=build(l,mid);
31         tr[x].rc=build(mid+1,r);
32     }
33     else tr[x].lc=tr[x].rc=0;
34     return x;
35 }
36 
37 void upd(int x)
38 {
39     tr[x].mx+=tr[x].lazy;
40     if(tr[x].lazy==0||tr[x].l==tr[x].r) {tr[x].lazy=0;return;}
41     int lc=tr[x].lc,rc=tr[x].rc;
42     tr[lc].lazy+=tr[x].lazy;
43     tr[rc].lazy+=tr[x].lazy;
44     tr[x].lazy=0;
45 }
46 
47 void change(int x,int l,int r,int y)
48 {
49     if(tr[x].l==l&&tr[x].r==r)
50     {
51         tr[x].lazy+=y;
52         upd(x);
53         return;
54     }
55     upd(x);
56     int mid=(tr[x].l+tr[x].r)>>1;
57     if(r<=mid) change(tr[x].lc,l,r,y);
58     else if(l>mid) change(tr[x].rc,l,r,y);
59     else
60     {
61         change(tr[x].lc,l,mid,y);
62         change(tr[x].rc,mid+1,r,y);
63     }
64     upd(tr[x].lc);upd(tr[x].rc);
65     tr[x].mx=mymax(tr[tr[x].lc].mx,tr[tr[x].rc].mx);
66 }
67 
68 int main()
69 {
70     int n,m;
71     scanf("%d%d",&n,&m);
72     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
73     for(int i=1;i<=m;i++) scanf("%d",&w[i]);
74     memset(ft,0,sizeof(ft));
75     for(int i=1;i<=n;i++)
76     {
77         nt[i]=ft[a[i]];
78         ft[a[i]]=i;
79     }
80     build(1,n);
81     LL maxx=0;
82     for(int i=1;i<=n;i++)
83     {
84         change(1,1,i,w[a[i]]);
85         if(nt[i]) change(1,1,nt[i],-2*w[a[i]]);
86         if(nt[nt[i]]) change(1,1,nt[nt[i]],w[a[i]]);
87         maxx=mymax(maxx,tr[1].mx);
88     }
89     printf("%lld\n",maxx);
90     return 0;
91 }
View Code

 

2017-04-08 10:54:12

【BZOJ 3747】 3747: [POI2015]Kinoman (线段树)