BZOJ 3747 洛谷 3582 [POI2015]Kinoman

【题解】

  扫描线+线段树。

  我们记第i部电影上次出现的位置是$pre[i]$,我们从$1$到$n$扫描,每次区间$(pre[i],i]$加上第i部电影的贡献$w[f[i]]$,区间$[pre[pre[i]],pre[i]]$减去第i部电影的贡献$w[f[i]]$.

  

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define N 1000010
 4 #define rg register
 5 #define ls (u<<1)
 6 #define rs (u<<1|1)
 7 #define mid ((l+r)>>1)
 8 #define LL long long
 9 using namespace std;
10 int n,m,f[N],w[N],pos[N],pre[N];
11 LL ans;
12 struct tree{
13     LL mx,del;
14 }a[N<<2];
15 inline int read(){
16     int k=0,f=1; char c=getchar();
17     while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
18     while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar();
19     return k*f;
20 }
21 inline LL max(LL x,LL y){
22     return x>y?x:y;
23 }
24 inline void pushup(int u){
25     a[u].mx=max(a[ls].mx,a[rs].mx);
26 }
27 inline void pushdown(int u){
28     if(!a[u].del) return;
29     LL d=a[u].del; a[u].del=0;
30     a[ls].mx+=d; a[ls].del+=d;
31     a[rs].mx+=d; a[rs].del+=d;
32 }
33 void add(int u,int ql,int qr,int l,int r,LL d){
34     //printf("%d %d %d %d
",ql,qr,l,r); 
35     if(ql<=l&&r<=qr){
36         a[u].del+=d; a[u].mx+=d; return;
37     }
38     pushdown(u);
39     if(ql<=mid) add(ls,ql,qr,l,mid,d);
40     if(qr>mid) add(rs,ql,qr,mid+1,r,d);
41     pushup(u);
42 }
43 int main(){
44     n=read(); m=read();
45     for(int i=1;i<=n;i++){
46         f[i]=read();
47         pre[i]=pos[f[i]]; pos[f[i]]=i;
48     }
49     for(int i=1;i<=m;i++) w[i]=read();
50     for(int i=1;i<=n;i++){
51         int prefix=pre[i];
52         add(1,prefix+1,i,1,n,w[f[i]]);
53         if(prefix) add(1,pre[prefix]+1,prefix,1,n,-w[f[i]]);
54         ans=max(ans,a[1].mx);
55     }
56     printf("%lld
",ans);
57     return 0;
58 }
View Code

  

原文地址:https://www.cnblogs.com/DriverLao/p/8669414.html