blogskol

思わず声に出して読みたくなるブログ

EDPC-W Intervals

W - Intervals

今回は1-indexedで考える
左から考えていくとした時、例えば、n=20として
01101001001010000??? の時100点
10100010000010000??? の時120点
といった具合にとる点数が確定している場合、上のパターンを答えとして採用することはありえない
なぜなら、残りの3文字により追加される点数はどちらも同じようになるから
具体的に考えると、18文字目を1にすることで新しく獲得する点数は

\sum \{ a_i | 13 < l_i \leq 18 \leq r_i \}

結局遷移は1が立ってる最も右端の場所のみから決まるので、
dp[i]:i番目が1でそれ以降0の時の最大値としてやればいい

遷移は

 dp [k ] = \max_{0 \leq i< k} dp[i ] + \{ a_j | i< l_j \leq k \leq r_j \}


dp[i ] + \{ a_j | i< l_j \leq k \leq r_j \}

を1つのNodeとして見れば動的な区間maxなのでセグ木を使いたくなる

\{ a_j | i < l_j \leq k \leq r_j \}

の挙動を考える
kが大きくなるとl_j側の制約は緩くなり、r_j側の制約が厳しくなることが分かる
そこで、kが上がるたび、
1.l_j側の制約を新たに満たしたものを加算
2.r_j側の制約を新たに破るものを減算
してやればいい

まず1について、dp[k]を更新する直前にlの制約を新たに満たすのはl=kなので、\sum \{a_j|l_j=k\}[0,k)に加算する
次に2について、dp[k]を更新する直前にrの制約を新たに破るのはr=k-1なので、各\{r_j=k-1\}について、1の加算をリセットする
すなわち、[0,l_j)-a_jを加算する

区間加算と区間maxなので、遅延セグ木を使うことで解ける
遅延セグ木のコード載せると見づらいので省略
ACコードには当然載せてあるので気になる人はそっち見て

#include <bits/stdc++.h>  
using namespace std;  
  
using ll=long long;  
struct P{int l;ll a;};  
ll L[200001],ans;  
vector<P> R[200001];  
  
int main(){  
  int n,m;cin>>n>>m;  
  while(m--){  
    int l,r,a;cin>>l>>r>>a;  
    L[l]+=a;  
    R[r].push_back({l,a});  
  }  
  seg;  
  /*  
  update(l,r,a):[l,r)にaを加算  
  query(l,r):[l,r)の最大値  
  set_val(i,S):i番目にSを代入  
  が出来る遅延セグ木  
  */  
  seg.set_val(0,0);  
  for(int i=1;i<=n;i++){  
    seg.update(0,i,L[i]);  
    ll S=seg.query(0,i);  
    if(ans<S)ans=S;  
    seg.set_val(i,S);  
    for(P p:R[i])seg.update(0,p.l,-p.a);  
  }  
  cout<<ans<<endl;  
}  

Submission #11367161 - Educational DP Contest