[ABC225] E - フ

[Q] https://atcoder.jp/contests/abc225/tasks/abc225_e
・そもそもフじゃなかった。

Q. フ?
A. 
____
   |
   |

・座標圧縮 + セグ木で500msくらいでした。

・問題の読み替え
範囲がたくさん与えられたときに、範囲の重複なくできるだけ多く取るにはどうすればいいか、という読み替えができる。

Q. たとえばこんな問題。

要素が5個あって、重複せずに何要素とれるか。
1 2
2 3
3 4
4 5
2 6

これは、
1--2
   2--3
      3--4
         4--5
   2----------6

1,2,3,44本をとればよさそう。

Q. どうやって求める?
A. セグ木。

1. 右端の大きいものから処理していく。
1) 2 6
   2----------6

右端 6 以上で取れる最大要素は、0個。
ここまでで、自分を含めてとれる要素数は 0+1 = 1個。
左端 seg[2] = 1 をメモ。

2) 4 5

         4--5
  [1]        [0]
   2----------6

右端 5 以上で取れる最大要素は、0個。
ここまでで、自分を含めてとれる要素数は 0+1 = 1個。
左端 seg[4] = 1 をメモ。


3) 3 4

      3--4
        [1]
         4--5
  [1]          [0]
   2----------6

右端 4 以上で取れる最大要素は、1個。
ここまでで、自分を含めてとれる要素数は 1+1 = 2個。
左端 seg[3] = 2 をメモ。

4) 2 3

   2--3
     [2]
      3--4
        [1]
         4--5
  [1]          [0]
   2----------6

右端 3 以上で取れる最大要素は、2個。
ここまでで、自分を含めてとれる要素数は 2+1 = 3個。
左端 seg[2] = 3 をメモ。

5) 1 2

1--2
  [3]
   2--3
     [2]
      3--4
        [1]
         4--5
  [1]          [0]
   2----------6

右端 2 以上で取れる最大要素は、3個。
ここまでで、自分を含めてとれる要素数は 3+1 = 4個。
左端 seg[1] = 4 をメモ。


segの最大値が4なので 4本。

1. それぞれのフについて、傾きの小 ~ 大を、範囲と読み換えることができる。
2. doubleの範囲そのままだとできないので、座標圧縮で整数化する。
3. 整数範囲が求まれば、最大値が大きいものから順番にセグ木処理すればよさそう。

実装

ld X[200010];
ld Y[200010];

int main(){
 cincout();
 
 ll N;
 cin >> N;
 rep(i, N){
   ll x, y;
   cin >> x >> y;
   X[i] = x;
   Y[i] = y;
 }
 
 vector<ld> V;
// 範囲の最小(d2) ~ 最大(d1)を求める。
 rep(i, N){
   ld x = X[i];
   ld y = Y[i];
   ld d1 = -oo;
   ld d2 = oo;
   
   // xy
   chmax(d1, y/x);
   chmin(d2, y/x);
   
   // x-1, y
   if (x>0){
     chmax(d1, y/(x-1));
     chmin(d2, y/(x-1));
   }
   else if (x==0){
     chmax(d1, oo);
   }
   
   // x, y-1
   chmax(d1, (y-1)/x);
   chmin(d2, (y-1)/x);
   
   V.push_back(d1);
   V.push_back(d2);
 }

 // 座圧
 comp<ld>(V);

// 範囲を、右端の大きい順に並べたい。pair<ll, ll>で管理。
 vector<pll> C; // sortしたい
 
 rep(i, N){ // V = {d1, d2, d1, d2...}
   ll v1=V[i*2];
   ll v2=V[i*2+1];
   C.push_back({v1, v2});
 }
 sort(all(C), greater<pll>());

// セグ木
 RangeMax Z;
 Z.init(400010); // N*2 要素まで入りうる
 Z.update(400005, 0);
 ll ans = 0;
 rep(i, N){
   ll up = C[i].first;
   ll down = C[i].second;
   
   ll high = Z.query(up, 400009);
   Z.update(down, high + 1); // id, val
   chmax(ans, high+1);
 }
 
 cout << ans << endl;
}

https://atcoder.jp/contests/abc225/submissions/26937252



この記事が気に入ったらサポートをしてみませんか?