bzoj3747: [POI2015]Kinoman
哇被靖靖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; }
pain and happy in the cruel world.