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;
}

 

posted @ 2018-04-02 20:55  AKCqhzdy  阅读(171)  评论(0编辑  收藏  举报