首页 > 代码库 > 【BZOJ 3747】 3747: [POI2015]Kinoman (线段树)
【BZOJ 3747】 3747: [POI2015]Kinoman (线段树)
3747: [POI2015]Kinoman
Time Limit: 60 Sec Memory Limit: 128 MB
Submit: 830 Solved: 338Description
共有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 6Sample 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 }
2017-04-08 10:54:12
【BZOJ 3747】 3747: [POI2015]Kinoman (线段树)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。