zoukankan      html  css  js  c++  java
  • [POI2015]Kinoman 解题报告 (线段树)

    [POI2015]Kinoman

    题意

    (m) 部电影, 每部电影有一个权值 (w[i]).

    (n) 天内, 每天会播放一部电影 (f[i]).

    若一部电影在区间 ([l,r]) (代表天数) 内出现了两次以上, 则无法获得它的权值.

    求能够获得的最大权值.


    思路

    先把左端点 (l) 放在 (1).

    当一部电影出现了两次后, 就无法获得它的权值, 那么, 一部电影的贡献范围就是一个区间.

    (nxt[i])(f[i]) 下一次出现的位置, 则 (i) 的贡献范围就是 ([i,nxt[i])) (注意是左开右闭), 且 (f[i]) 没有在 (i) 之前的位置出现.

    (l=1) 时, 我们用线段树区间修改, 把每部电影的贡献添加到它对应的区间上, 然后区间查询最大值即可.

    (l) 往右移动时, 设 (l-1=i), 那么就把 ([i,nxt[i])) 的贡献减去, 加上 ([nxt[i],nxt[nxt[i]])) 的贡献, 然后再查询最大值即可.


    代码

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int _=1e6+7;
    const int __=4e6+7;
    int n,m,film[_],wgt[_],nxt[_],las[_];
    ll maxn[__],tag[__],ans;
    bool vis[_];
    void upd(int k,ll w){
      maxn[k]+=w;
      tag[k]+=w;
    }
    void push_down(int k){
      if(!tag[k]) return;
      upd(k<<1,tag[k]);
      upd(k<<1|1,tag[k]);
      tag[k]=0;
    }
    void modify(int k,int l,int r,int x,int y,ll w){
      if(l>=x&&r<=y){ upd(k,w); return; }
      push_down(k);
      int mid=(l+r)>>1;
      if(x<=mid) modify(k<<1,l,mid,x,y,w);
      if(y>mid) modify(k<<1|1,mid+1,r,x,y,w);
      maxn[k]=max(maxn[k<<1],maxn[k<<1|1]);
    }
    ll query(int k,int l,int r,int x,int y){
      if(l>=x&&r<=y) return maxn[k];
      push_down(k);
      int mid=(l+r)>>1;
      ll t1=0,t2=0;
      if(x<=mid) t1=query(k<<1,l,mid,x,y);
      if(y>mid) t2=query(k<<1|1,mid+1,r,x,y);
      return max(t1,t2);
    }
    int main(){
    #ifndef ONLINE_JUDGE
      freopen("x.in","r",stdin);
    #endif
      cin>>n>>m;
      for(int i=1;i<=n;i++) scanf("%d",&film[i]);
      for(int i=1;i<=m;i++){ scanf("%d",&wgt[i]); las[i]=n+1; }
      for(int i=n;i>=1;i--){
        nxt[i]=las[film[i]];
        las[film[i]]=i;
      }
      for(int i=1;i<=n;i++)
        if(!vis[film[i]]){
          modify(1,1,n,i,nxt[i]-1,wgt[film[i]]);
          vis[film[i]]=1;
        }
      for(int l=1;l<=n;l++){
        ans=max(ans,query(1,1,n,l,n));
        modify(1,1,n,l,nxt[l]-1,(ll)-wgt[film[l]]);
        modify(1,1,n,nxt[l],nxt[nxt[l]]-1,(ll)wgt[film[l]]);
      }
      printf("%lld
    ",ans);
      return 0;
    }
    
  • 相关阅读:
    读书笔记五
    读书笔记四
    读书笔记3(Teamwork)
    读书笔记二(合格的软件工程师)
    读书笔记1(软件 = 程序 + 工程)
    关于使用Java开发Mis系统
    课堂动手动脑
    Quartz学习
    把数据库中取出的DataTable转换成一个对象 或者对象列表
    SAE上使用cron定时发微博
  • 原文地址:https://www.cnblogs.com/BruceW/p/12188184.html
Copyright © 2011-2022 走看看