BZOJ 3747 Kinoman

和HEOI采花类似。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 1000050
using namespace std;
int n,m,f[maxn],w[maxn],regis[maxn],nxt[maxn];
int root,tot=0,ls[maxn<<2],rs[maxn<<2],cnt[maxn];
long long lazy[maxn<<2],mx[maxn<<2],val[maxn],ans=0;
int read()
{
    int data=0;char ch;
    while (ch<‘0‘ || ch>‘9‘) ch=getchar();
    while (ch>=‘0‘ && ch<=‘9‘)
    {
        data=data*10+ch-‘0‘;
        ch=getchar();
    }
    return data;
}
void get_table()
{
    long long ret=0;
    for (int i=1;i<=n;i++)
    {
        cnt[f[i]]++;
        if (cnt[f[i]]==1) ret+=w[f[i]];
        else if (cnt[f[i]]==2) ret-=w[f[i]];
        val[i]=ret;
    }
    for (int i=n;i>=1;i--)
    {
        if (!regis[f[i]]) nxt[i]=n+1;
        else nxt[i]=regis[f[i]];
        regis[f[i]]=i;
    }
}
void build(int &now,int left,int right)
{
    now=++tot;lazy[now]=0;
    if (left==right)
    {
        mx[now]=val[left];
        return;
    }
    int mid=left+right>>1;
    build(ls[now],left,mid);
    build(rs[now],mid+1,right);
    mx[now]=max(mx[ls[now]],mx[rs[now]]);
}
void pushdown(int now)
{
    if (lazy[now]==0) return;
    lazy[ls[now]]+=lazy[now];lazy[rs[now]]+=lazy[now];
    mx[ls[now]]+=lazy[now];mx[rs[now]]+=lazy[now];
    lazy[now]=0;
}
long long ask(int now,int left,int right,int l,int r)
{
    pushdown(now);
    if ((left==l) && (right==r)) return mx[now];
    int mid=left+right>>1;
    if (r<=mid) return ask(ls[now],left,mid,l,r);
    else if (l>=mid+1) return ask(rs[now],mid+1,right,l,r);
    else return max(ask(ls[now],left,mid,l,mid),ask(rs[now],mid+1,right,mid+1,r));
}
void modify(int now,int left,int right,int l,int r,int x)
{
    if (l>r) return;
    pushdown(now);
    if ((left==l) && (right==r))
    {
        lazy[now]+=x;mx[now]+=x;
        return;
    }
    int mid=left+right>>1;
    if (r<=mid) modify(ls[now],left,mid,l,r,x);
    else if (l>=mid+1) modify(rs[now],mid+1,right,l,r,x);
    else
    {
        modify(ls[now],left,mid,l,mid,x);
        modify(rs[now],mid+1,right,mid+1,r,x);
    }
    mx[now]=max(mx[ls[now]],mx[rs[now]]);
}
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();
    get_table();
    build(root,1,n);
    for (int i=1;i<=n;i++)
    {
        ans=max(ans,ask(root,1,n,i,n));
        modify(root,1,n,i,nxt[i]-1,-w[f[i]]);
        modify(root,1,n,nxt[i],nxt[nxt[i]]-1,w[f[i]]);
    }
    printf("%lld\n",ans);
    return 0;
}
时间: 2024-12-28 01:28:26

BZOJ 3747 Kinoman的相关文章

[BZOJ 3747] [POI 2015] Kinoman【线段树】

Problem Link : BZOJ 3747 题解:ZYF-ZYF 神犇的题解 解题的大致思路是,当区间的右端点向右移动一格时,只有两个区间的左端点对应的答案发生了变化. 从 f[i] + 1 到 i 的区间中的答案增加了 W[A[i]], 从 f[f[i]] + 1 到 f[i] 的区间的答案减少了 W[A[i]] ,其余区间的答案没有发生变化. 那么就是线段树的区间修改和区间最值查询. 代码如下: #include <iostream> #include <cstdio>

BZOJ 3747: [POI2015]Kinoman( 线段树 )

线段树... 我们可以枚举左端点 , 然后用线段树找出所有右端点中的最大值 . ----------------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #define rep( i , n ) for( i

【BZOJ 3747】 3747: [POI2015]Kinoman (线段树)

3747: [POI2015]Kinoman Time Limit: 60 Sec  Memory Limit: 128 MBSubmit: 830  Solved: 338 Description 共有m部电影,编号为1~m,第i部电影的好看值为w[i]. 在n天之中(从1~n编号)每天会放映一部电影,第i天放映的是第f[i]部. 你可以选择l,r(1<=l<=r<=n),并观看第l,l+1,-,r天内所有的电影.如果同一部电影你观看多于一次,你会感到无聊,于是无法获得这部电影的好看值

BZOJ 3747 POI 2015 Kinoman 线段树

题目大意:给出电影院的放映电影顺序,一个电影只有看过一次的时候会获得电影的权值.没看过或者看两次或以上都不能获得权值.问看连续区间的电影能够获得的最大权值是多少. 思路:利用线段树维护前缀和.将出现第一次的地方的权值加上那部电影的权值,第二次出现的时候权值减去那部电影的权值.枚举起点,先更新答案,然后在当前节点减去权值的二倍,然后再在下一次出现的地方加上权值(我感觉我没说明白,总之看代码吧... CODE: #include <cstdio> #include <cstring>

BZOJ 3747 POI2015 Kinoman

因为上午没有准备够题目,结果发现写完这道题没题可写了QAQ 又因为这道题范围是100w,我写了发线段树,以为要T,上午就花了一个小时拼命卡常数 结果下午一交居然过了QAQ 我们考虑枚举L,求最大R使得[L,R]是对于当前L最大权值的区间 考虑每个点的影响 如果从L向右他是第一个,那么他会对后面产生a[f[L]]的贡献 如果从L向右他是第二个,那么他会对后面产生-a[f[L]]的贡献 然后我们维护一棵线段树,每次查询最值并且进行更新即可 include<cstdio> #include<i

BZOJ 3747: [POI2015]Kinoman 【线段树】

Description 共有m部电影,编号为1~m,第i部电影的好看值为w[i]. 在n天之中(从1~n编号)每天会放映一部电影,第i天放映的是第f[i]部. 你可以选择l,r(1<=l<=r<=n),并观看第l,l+1,…,r天内所有的电影.如果同一部电影你观看多于一次,你会感到无聊,于是无法获得这部电影的好看值.所以你希望最大化观看且仅观看过一次的电影的好看值的总和. Input 第一行两个整数n,m(1<=m<=n<=1000000). 第二行包含n个整数f[1]

@bzoj - [email&#160;protected] [POI2015] Kinoman

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 共有 m 部电影,第 i 部电影的好看值为 w[i]. 在 n 天之中每天会放映一部电影,第 i 天放映的是第 f[i] 部. 你可以选择 l, r (1 <= l <= r <= n) ,并观看第 l, l+1, -, r 天内所有的电影. 最大化观看且仅观看过一次的电影的好

3747: [POI2015]Kinoman|线段树

枚举左区间线段树维护最大值 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<vector> #include<cmath> #include<queue> #include<set> #include<map> #define ll l

【BZOJ-3747】Kinoman 线段树

3747: [POI2015]Kinoman Time Limit: 60 Sec  Memory Limit: 128 MBSubmit: 715  Solved: 294[Submit][Status][Discuss] Description 共有m部电影,编号为1~m,第i部电影的好看值为w[i]. 在n天之中(从1~n编号)每天会放映一部电影,第i天放映的是第f[i]部. 你可以选择l,r(1<=l<=r<=n),并观看第l,l+1,…,r天内所有的电影.如果同一部电影你观看多