BZOJ 3747: [POI2015]Kinoman

20 篇文章 0 订阅

都说是经典题。嗯我也觉得是 然而我太菜了。。
一开始在想O(n)的做法 想不到 难道是nlogn?
看了看status个个都挺慢的啊 本来就是要nlogn。。

原来直接暴力上线段树搞就好了 (线段树维护这个点为起点到i的答案
p[i]表示上次这个数出现的时间 我们枚举右端点,每次加入一个数,那么p[i]+1到i这段位置的答案加上这个数的权值,p[p[i]]+1到p[i]这段位置的答案减去这个数的权值,然后查询[1,i]的最大值即可。

这次看来是打搓了。。跑的好慢啊QAQ

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1000002;
inline int read(){
    char ch=getchar(); int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0'; ch=getchar();}
    return x*f;
}
int a[N],w[N],p[N],z[N]; LL s[N<<2],lz[N<<2];
void pd(int x){
    int lc=x<<1,rc=lc|1; LL u=lz[x]; lz[x]=0;
    s[lc]+=u,lz[lc]+=u,s[rc]+=u,lz[rc]+=u;
}
void g(int x,int l,int r,int ql,int qr,int u){
    if(ql>r || qr<l || ql>qr)return;
    if(ql<=l&&r<=qr){lz[x]+=u,s[x]+=u; return;}
    pd(x); int lc=x<<1,rc=lc|1,mid=(l+r)>>1;
    g(lc,l,mid,ql,qr,u),g(rc,mid+1,r,ql,qr,u);
    s[x]=max(s[lc],s[rc]);
}
LL c(int x,int l,int r,int ql,int qr){
    if(ql>r || qr<l)return 0;
    if(ql<=l&&r<=qr)return s[x];
    pd(x); int lc=x<<1,rc=lc|1,mid=(l+r)>>1;
    return max(c(lc,l,mid,ql,qr),c(rc,mid+1,r,ql,qr));
}
int main()
{
    int n=read(),m=read(),i;
    for(i=1;i<=n;i++)a[i]=read(),p[i]=z[a[i]],z[a[i]]=i;
    for(i=1;i<=m;i++)w[i]=read();
    LL ans=0;
    for(i=1;i<=n;i++){
        g(1,1,n,p[p[i]]+1,p[i],-w[a[i]]);
        g(1,1,n,p[i]+1,i,w[a[i]]);
        ans=max(c(1,1,n,1,i),ans);
    }
    printf("%lld\n",ans);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值