共有m部电影,编号为1~m,第i部电影的好看值为w[i]。
在n天之中(从1~n编号)每天会放映一部电影,第i天放映的是第f[i]部。
你可以选择l,r(1<=l<=r<=n),并观看第l,l+1,…,r天内所有的电影。如果同一部电影你观看多于一次,你会感到无聊,于是无法获得这部电影的好看值。所以你希望最大化观看且仅观看过一次的电影的好看值的总和。
标签:
#include<cstdio> #include<iostream> #define LL long long using namespace std; inline LL read() { LL x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } int w[1000010],f[1000010]; int lst[1000010],nxt[1000010]; int n,m; LL ans; struct segtree{int l,r;LL tag,mx;}tree[4000010]; inline void pushdown(int k) { if (tree[k].l==tree[k].r)return; LL tag=tree[k].tag;tree[k].tag=0; if (tag) { tree[k<<1].mx+=tag; tree[k<<1].tag+=tag; tree[k<<1|1].mx+=tag; tree[k<<1|1].tag+=tag; } } inline void buildtree(int now,int l,int r) { tree[now].l=l;tree[now].r=r; if (l==r)return; int mid=(l+r)>>1; buildtree(now<<1,l,mid); buildtree(now<<1|1,mid+1,r); } inline void add(int now,int x,int y,int d) { if (tree[now].tag)pushdown(now); int l=tree[now].l,r=tree[now].r; if (l==x&&r==y) { tree[now].tag+=d; tree[now].mx+=d; return; } int mid=(l+r)>>1; if (y<=mid)add(now<<1,x,y,d); else if (x>mid)add(now<<1|1,x,y,d); else { add(now<<1,x,mid,d); add(now<<1|1,mid+1,y,d); } tree[now].mx=max(tree[now<<1].mx,tree[now<<1|1].mx); } int main() { n=read();m=read(); for(int i=1;i<=n;i++)f[i]=read(); for(int i=1;i<=m;i++)w[i]=read(); for (int i=n;i>=1;i--) { nxt[i]=lst[f[i]]; lst[f[i]]=i; } buildtree(1,1,n); for(int i=1;i<=m;i++) if (lst[i]) { if (!nxt[lst[i]])add(1,lst[i],n,w[i]); else add(1,lst[i],nxt[lst[i]]-1,w[i]); } for (int i=1;i<=n;i++) { ans=max(ans,tree[1].mx); int to=nxt[i]; if (to) { add(1,i,to-1,-w[f[i]]); if (nxt[to])add(1,to,nxt[to]-1,w[f[i]]); else add(1,to,n,w[f[i]]); }else add(1,i,n,-w[f[i]]); } printf("%lld\n",ans); return 0; }
标签:
原文地址:http://www.cnblogs.com/zhber/p/4175810.html