結果
| 問題 |
No.1170 Never Want to Walk
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2020-08-14 23:16:09 |
| 言語 | C++14 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 177 ms / 2,000 ms |
| コード長 | 4,571 bytes |
| コンパイル時間 | 1,984 ms |
| コンパイル使用メモリ | 185,908 KB |
| 実行使用メモリ | 6,820 KB |
| 最終ジャッジ日時 | 2024-10-10 16:40:18 |
| 合計ジャッジ時間 | 5,670 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 |
| other | AC * 37 |
ソースコード
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr char newl = '\n';
struct UnionFind {
//各要素が属する集合の代表(根)を管理する
//もし、要素xが根であればdata[x]は負の値を取り、-data[x]はxが属する集合の大きさに等しい
vector<int> data;
UnionFind(int sz) : data(sz, -1) {}
bool unite(int x, int y) {
x = find(x);
y = find(y);
bool is_union = (x != y);
if (is_union) {
if (data[x] > data[y]) swap(x, y);
data[x] += data[y];
data[y] = x;
}
return is_union;
}
int find(int x) {
if (data[x] < 0) { //要素xが根である
return x;
} else {
data[x] = find(data[x]); //data[x]がxの属する集合の根でない場合、根になるよう更新される
return data[x];
}
}
bool same(int x, int y) {
return find(x) == find(y);
}
int size(int x) {
return -data[find(x)];
}
};
// https://satanic0258.github.io/snippets/data-structure/SegmentMap.html
// Description: 区間をsetで管理するデータ構造(なお実装はmap).各クエリO(log区間数).
// #### attention! : [l, r] ( include r, not [l, r) )
class SegmentMap : public std::map<signed, signed> {
private:
bool flagToMergeAdjacentSegment;
public:
// if merge [l, c] and [c+1, r], set flagToMergeAdjacentSegment to true
SegmentMap(bool flagToMergeAdjacentSegment) :
flagToMergeAdjacentSegment(flagToMergeAdjacentSegment) {}
// __exist -> iterator pair(l, r) (contain p)
// noexist -> map.end()
auto get(signed p) const {
auto it = upper_bound(p);
if (it == begin() || (--it)->second < p) return end();
return it;
}
// insert segment [l, r]
void insert(signed l, signed r) {
auto itl = upper_bound(l), itr = upper_bound(r + flagToMergeAdjacentSegment);
if (itl != begin()) {
if ((--itl)->second < l - flagToMergeAdjacentSegment) ++itl;
}
if (itl != itr) {
l = std::min(l, itl->first);
r = std::max(r, std::prev(itr)->second);
erase(itl, itr);
}
(*this)[l] = r;
}
// remove segment [l, r]
void remove(signed l, signed r) {
auto itl = upper_bound(l), itr = upper_bound(r);
if (itl != begin()) {
if ((--itl)->second < l) ++itl;
}
if (itl == itr) return;
int tl = std::min(l, itl->first), tr = std::max(r, std::prev(itr)->second);
erase(itl, itr);
if (tl < l) (*this)[tl] = l - 1;
if (r < tr) (*this)[r + 1] = tr;
}
// Is p and q in same segment?
bool same(signed p, signed q) const {
const auto&& it = get(p);
return it != end() && it->first <= q && q <= it->second;
}
};
int main() {
cin.tie(nullptr);
ios::sync_with_stdio(false);
int n;
ll a, b;
cin >> n >> a >> b;
vector<ll> x(n);
for (int i = 0; i < n; i++) {
cin >> x[i];
}
SegmentMap sm(false);
UnionFind uf(n);
for (int i = 0; i < n; i++) {
if (sm.get(i) != sm.end()) {
continue;
}
queue<int> q;
q.push(i);
sm.insert(i, i);
while (!q.empty()) {
int k = q.front();
q.pop();
{
int L = lower_bound(x.begin(), x.end(), x[k] - b) - x.begin();
int R = upper_bound(x.begin(), x.end(), x[k] - a) - x.begin();
for (int j = L; j < R; j++) {
if (sm.get(j) != sm.end()) {
j = sm.get(j)->second;
continue;
}
q.push(j);
uf.unite(k, j);
}
if (L < R) sm.insert(L, R - 1);
}
{
int L = lower_bound(x.begin(), x.end(), x[k] + a) - x.begin();
int R = upper_bound(x.begin(), x.end(), x[k] + b) - x.begin();
for (int j = L; j < R; j++) {
if (sm.get(j) != sm.end()) {
j = sm.get(j)->second;
continue;
}
q.push(j);
uf.unite(k, j);
}
if (L < R) sm.insert(L, R - 1);
}
}
}
for (int i = 0; i < n; i++) {
cout << uf.size(i) << newl;
}
return 0;
}