joig2022_e 题解

设计 \(f_i\) 表示以第 \(i\) 个数结尾的选择的最大值。

\(f_i = f_j + a_i\)\(type_i \not = type_j\))。

发现可以选择的种类其实构成两段连续区间。

所以维护使得 \(type_x = i\) 的所有 \(x\)\(f_x\) 最大值。

这个用线段树可以很简洁的维护。

于是就 \(O(n \log n)\) 地做完了。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int inf = 1e18+7;
const int maxn=150010;
int dp[maxn];
int type[maxn],a[maxn],n,m,ans;
int tree[maxn*4];
void pushup(int x)
{
  tree[x]=max(tree[x*2],tree[x*2+1]);
}
void add(int now,int val,int l,int r,int x)
{
  if(l==r)
  {
    tree[x]+=val;
    return ;
  }
  int mid=(l+r)/2;
  if(now<=mid)
    add(now,val,l,mid,x*2);
  else
    add(now,val,mid+1,r,x*2+1);
  pushup(x);
  return ;
}
int question(int L,int R,int l,int r,int x)
{
  if(R>n||L<1||R<L)
    return 0;
  if(L<=l&&R>=r)
  {
    return tree[x];
  }
  int mid=(l+r)/2,res=-inf;
  if(L<=mid)
    res=max(res,question(L,R,l,mid,x*2));
  if(R>mid)
    res=max(res,question(L,R,mid+1,r,x*2+1));
  return res;
}
signed main()
{
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  for(int i=0;i<maxn*4;i++) tree[i]=-inf; 
  cin>>n>>m;
  for(int i=1;i<=n;i++)
    cin>>type[i]>>a[i];
  dp[1]=a[1];
  ans=max(ans,dp[1]);
  add(type[1],inf,1,m,1);
  add(type[1],a[1],1,m,1);
  for(int i=2;i<=n;i++)
  {
      dp[i]=max(question(1,type[i]-1,1,m,1),max(question(type[i]+1,m,1,m,1),0*1ll))+a[i];
      if(dp[i]>question(type[i],type[i],1,m,1))
      {
        int u=question(type[i],type[i],1,m,1);
        add(type[i],-u,1,m,1);
        add(type[i],dp[i],1,m,1);
      }
      ans=max(ans,dp[i]);
  }
  cout<<ans;
}
posted @ 2024-01-30 23:57  ChiFAN鸭  阅读(5)  评论(0编辑  收藏  举报