1. 程式人生 > >bzoj3747: [POI2015]Kinoman

bzoj3747: [POI2015]Kinoman

man color csdn num class jin bzoj3747 return oid

哇被靖靖D飛啊

這題做法很是玄學,感覺最近這段時間的確是比較頹,一點寫大數據結構的欲望都沒有。

首先先用一個鏈表存儲同一部電影的出現時間。

然後求前綴和。

枚舉左端點往右延伸,電影的出現次數也減少,判斷一下加減的情況即可。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long
long LL; struct trnode { int l,r,lc,rc;LL c,lazy; }tr[2100000];int trlen; void bt(int l,int r) { trlen++;int now=trlen; tr[now].l=l;tr[now].r=r; tr[now].lc=tr[now].rc=-1; tr[now].c=0;tr[now].lazy=0; if(l<r) { int mid=(l+r)/2; tr[now].lc=trlen+1
;bt(l,mid); tr[now].rc=trlen+1;bt(mid+1,r); tr[now].c=max(tr[tr[now].lc].c,tr[tr[now].rc].c); } } void change(int now,int l,int r,LL k) { if(l>r)return ; if(tr[now].l==l&&tr[now].r==r) { tr[now].c+=k; tr[now].lazy+=k; return
; } int lc=tr[now].lc,rc=tr[now].rc; int mid=(tr[now].l+tr[now].r)/2; if(tr[now].lazy!=0) { tr[lc].c+=tr[now].lazy;tr[lc].lazy+=tr[now].lazy; tr[rc].c+=tr[now].lazy;tr[rc].lazy+=tr[now].lazy; tr[now].lazy=0; } if(r<=mid)change(lc,l,r,k); else if(mid+1<=l)change(rc,l,r,k); else change(lc,l,mid,k),change(rc,mid+1,r,k); tr[now].c=max(tr[lc].c,tr[rc].c); } LL findmax(int now,int l,int r) { if(tr[now].l==l&&tr[now].r==r)return tr[now].c; int lc=tr[now].lc,rc=tr[now].rc; int mid=(tr[now].l+tr[now].r)/2; if(tr[now].lazy!=0) { tr[lc].c+=tr[now].lazy;tr[lc].lazy+=tr[now].lazy; tr[rc].c+=tr[now].lazy;tr[rc].lazy+=tr[now].lazy; tr[now].lazy=0; } if(r<=mid)return findmax(lc,l,r); else if(mid+1<=l)return findmax(rc,l,r); else return max(findmax(lc,l,mid),findmax(rc,mid+1,r)); } int f[1100000]; int num[1100000],next[1100000],first[1100000]; LL s[1100000],w[1100000]; int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&f[i]); for(int i=1;i<=m;i++)scanf("%d",&w[i]); memset(first,0,sizeof(first)); for(int i=n;i>=1;i--) { next[i]=first[f[i]]; first[f[i]]=i; } for(int i=1;i<=n;i++) { s[i]=s[i-1]; if(num[f[i]]==0)s[i]+=w[f[i]]; if(num[f[i]]==1)s[i]-=w[f[i]]; num[f[i]]++; } trlen=0;bt(1,n); for(int i=1;i<=n;i++)change(1,i,i,s[i]); LL ans=0; for(int i=1;i<=n;i++) { ans=max(ans,findmax(1,i,n)); if(next[i]!=0) { change(1,i+1,next[i]-1,-w[f[i]]); if(next[next[i]]!=0) change(1,next[i],next[next[i]]-1,w[f[i]]); else change(1,next[i],n,w[f[i]]); } else change(1,i+1,n,-w[f[i]]); } printf("%lld\n",ans); return 0; }

bzoj3747: [POI2015]Kinoman