[POI2015] KIN/Kinoman ——线段树入门
[POI2015] KIN
题目描述
共有 \(m\) 部电影,编号为 \(1,2,\ldots,m\),第 \(i\) 部电影的好看值为 \(w_i\)。
在 \(n\) 天之中,每天会放映一部电影,第 \(i\) 天放映的是第 \(f_i\) 部。
你可以选择 \(l,r\)(\(1\le l\le r\le n\)),并观看第 \(l,l+1,\ldots,r\) 天内所有的电影。
但如果同一部电影你观看多于一次,你会感到无聊,于是无法获得这部电影的好看值。
现在,您需要最大化观看且仅观看过一次的电影的好看值的总和。
输入格式
第一行两个整数 \(n,m\)。
第二行包含 \(n\) 个整数,第 \(i\) 个表示 \(f_i\)。
第三行包含 \(m\) 个整数,第 \(i\) 个表示 \(w_i\)。
输出格式
一行一个整数,表示仅观看过一次的电影的好看值的总和的最大值。
样例 #1
样例输入 #1
9 4
2 3 1 1 4 1 2 4 1
5 3 6 6
样例输出 #1
15
提示
【数据范围】
对于 \(100\%\) 的数据,\(1\le m\le n\le 10^6\),\(1\le f_i\le m\),\(1\le w_i\le 10^6\)。
原题名称:Kinoman。
分析
对于每种电影只有最后两处有用。在最后一处打上正标记,倒数第二处打上负标记,求最大右区间和即可。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+100;
int n,m,g[N],lef[N];
long long val[N],all,ans;
int tot[N],rec[N],num[N];
int pos[N][2];
struct segtree
{
long long val;
long long rsum;
}s[N<<2];
void pushup(segtree &t,segtree &a,segtree &b)//cong you kai shi de zui da qu jian he
{
t.val=a.val+b.val;
t.rsum=max( b.rsum,b.val+a.rsum );
}
void upd(int i,int l,int r,int x,long long z)
{
if(l==r)
{
s[i].rsum=s[i].val=z;
return ;
}
int mid=(l+r)>>1;
if(x<=mid)upd(i<<1,l,mid,x,z);
else upd(i<<1|1,mid+1,r,x,z);
pushup(s[i],s[i<<1],s[i<<1|1]);
}
inline void eq(segtree &a,long long b,long long c)
{
a.val=b;
a.rsum=c;
}
segtree que(int i,int l,int r,int x,int y)//query [x,y]
{
if(l>=x && r<=y)
return s[i];
int mid=(l+r)>>1;
segtree lc,rc,nw;
eq(lc,0,0);eq(rc,0,0);eq(nw,0,0);
if(x<=mid)lc=que(i<<1,l,mid,x,y);
if(y>mid)rc=que(i<<1|1,mid+1,r,x,y);
pushup(nw,lc,rc);
return nw;
}
void work()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)scanf("%d",&g[i]);
for(int i=1;i<=m;++i){scanf("%lld",&val[i]);all+=val[i];}
for(int i=1;i<=n;++i)//record the last two g[i]
{
//rec[ 1 ~ m ]
lef[i]=rec[g[i]];
++num[g[i]];
long long v=val[g[i]];
if(num[g[i]]==1)
{
pos[g[i]][0]=i;
upd(1,1,n,i,v);
}
else if(num[g[i]]==2)
{
upd(1,1,n,pos[g[i]][0],-v);
pos[g[i]][1]=i;
upd(1,1,n,i,v);
}
else
{
upd(1,1,n,pos[g[i]][0],0);
pos[g[i]][0]=pos[g[i]][1];
upd(1,1,n,pos[g[i]][1],-v);
pos[g[i]][1]=i;
upd(1,1,n,i,v);
}
segtree node=que(1,1,n,lef[i]+1,i);
ans=max(ans,node.rsum);
rec[g[i]]=i;
}
cout<<ans;
}
int main()
{
work();
return 0;
}
本文来自博客园,作者:Glowingfire,转载请注明原文链接:https://www.cnblogs.com/Glowingfire/p/18511773