F - Rectilinear Polygons

[Q] https://atcoder.jp/contests/abc211/tasks/abc211_f

解説AC。すごい。
https://www.youtube.com/watch?v=f3qwIMEoEbg&feature=youtu.be

二次元座標だけど、BITするのはy座標だけ。
クエリをx座標でソートして、xを0から100000まで探索する過程で、BITのyを適応させつつクエリ消化すれば、一次元(y座標)管理だけでおさまる。

1. 多角形を時計回りにそろえる。
2. x座標ごとに、y座標のデータを格納する。
3. xを0から100000まで動かして、BITを適応しつつ、クエリを消化する。

Q. 時計回り?

A. 入力例1を考える。
4
1 2 1 4 3 4 3 2
4
2 5 2 3 5 3 5 51 2 1 4 3 4 3 2
↑→↓←の書き方なので、これは時計回り。
上昇するときに+1, 下降するときに-1の判定。

・2 5 2 3 5 3 5 5
↓→↑←なので反時計回り。逆転処理の対象。

{x,y}をpairで入れてsortすれば、座標の左下の始点が取れる。
始点から上にいけば時計回り、右にいけば反時計回りと判断する。

Q. BIT?
A. テンプレートを利用。
BITはadd(0, 1)をすると無限ループしてしまう(index0を渡すとだめ)
Bit.addの中で、index+1対応しているので、直接datの中身を見るときは注意。
dat[0]を見たかったら、dat[1]がそれ。

実装

// BIT,index = 1 ~ (0を投げるととまる
// indexを+1して格納する。
// https://atcoder.jp/contests/abc174/submissions/21572028 #define  BT 100010
struct Bit
{
 ll dat[BT];
 Bit() {
   rep(i,BT) dat[i] = 0;
 }
 void add(ll i, ll x){
   ++i;
   for(; i<BT; i += i&-i) dat[i] += x;
 }
 ll sum(ll i){
   ++i;
   ll res = 0;
   for(; i>0; i -= i&-i) res += dat[i];
   return res;
 }
 ll rangesum(ll L, ll R){
   ++L, ++R;
   return sum(R) - sum(L-1);
 }
};

int main(){
 cincout();
 
 vector<pll> event[BT]; // event[x] = {y1, y2}
 ll N;
 cin >> N;
 rep(i, N){
   ll M;
   cin >> M;
   // 時計回りにしたい。(解説Vと逆回転。左下を原点とみなして判断。
   // 左下を見つける。右に行くようなら、逆転させたい。
   // 上プラス、下マイナス。
   vector<pll> P(M);
   rep(j, M) cin >> P[j].first >> P[j].second;
   ll s=0;
   rep(j, M) if(P[j] < P[s]) s=j; // 左下を見つけたい。
   rotate(P.begin(), P.begin()+s, P.end()); // 左下をスタート地点にする
   if (P[0].first != P[1].first) reverse(P.begin()+1, P.end()); // 右にいっちゃうなら回転を逆にする
   for(ll j=0; j<M; j+=2){
     event[P[j].first].push_back({P[j].second, P[j+1].second});
   }
 }
 
 ll Q;
 cin >> Q;
 ll ans[Q] = {};
 ll Y[Q] = {};
 vector<pll> VQ(Q);
 rep(i, Q){
   ll x;
   cin >> x >> Y[i];
   VQ[i] = {x, i}; // xでsort。indexを残したい
 }
 sort(all(VQ));

 Bit bits;
 ll q=0;
 rep(i, 100001){
   for(auto p: event[i]){
     ll w=1;
     ll down=p.first, up=p.second;
     if (up < down){ // 上から下にいくからマイナス
       swap(up, down);
       w=-1;
     }
     bits.add(down, w); // down==0だと壊れるからbitで+1判定
     bits.add(up, -w);
   }
   while (q<Q && VQ[q].first == i){
     ll id=VQ[q].second;
     ans[id] = bits.sum(Y[id]);
     ++q;
   }
   if (q==Q) break;
 }
 rep(i, Q) cout << ans[i] << endl;
}

https://atcoder.jp/contests/abc211/submissions/26066032



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