結果
| 問題 |
No.880 Yet Another Segment Tree Problem
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2020-02-10 06:23:47 |
| 言語 | D (dmd 2.109.1) |
| 結果 |
AC
|
| 実行時間 | 1,401 ms / 5,000 ms |
| コード長 | 10,385 bytes |
| コンパイル時間 | 3,245 ms |
| コンパイル使用メモリ | 163,120 KB |
| 実行使用メモリ | 27,076 KB |
| 最終ジャッジ日時 | 2025-06-20 10:31:50 |
| 合計ジャッジ時間 | 36,511 ms |
|
ジャッジサーバーID (参考情報) |
judge4 / judge1 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 1 |
| other | AC * 38 |
コンパイルメッセージ
/home/linuxbrew/.linuxbrew/opt/dmd/include/dlang/dmd/std/numeric.d(2999): Warning: cannot inline function `std.numeric.gcdImpl!ulong.gcdImpl`
ソースコード
import std.stdio;
import std.string;
import std.format;
import std.conv;
import std.typecons;
import std.algorithm;
import std.functional;
import std.bigint;
import std.numeric;
import std.array;
import std.math;
import std.range;
import std.container;
import std.concurrency;
import std.traits;
import std.uni;
import core.bitop : popcnt;
alias Generator = std.concurrency.Generator;
enum long INF = long.max/5;
enum long MOD = 10L^^9+7;
void main() {
long N, Q;
scanln(N, Q);
long[] as = readln.split.to!(long[]);
struct M {
long maxValue;
long num;
long sumValue;
bool multiple;
long lcmValue;
}
struct X {
bool isGcd;
long x;
}
long lcm(long a, long b) {
import core.checkedint;
if (a == -1 || b == -1) return -1;
if (a*b == 0) return -1;
bool overflow;
long c = muls(a/gcd(a, b), b, overflow);
if (overflow) return -1;
if (c > long.max/100) return -1;
return c;
}
auto seg = LazySegTree!(
M, X,
(M a, M b) {
return M(
max(a.maxValue, b.maxValue),
a.num + b.num,
a.sumValue + b.sumValue,
a.multiple || b.multiple || (
a.maxValue != b.maxValue && a.maxValue != -INF && b.maxValue != -INF
),
lcm(a.lcmValue, b.lcmValue)
);
},
(X a, X b) {
if (b.x == -1) {
return a;
} else if (!b.isGcd || a.x == -1) {
return b;
} else if (!a.isGcd) {
return X(false, gcd(a.x, b.x));
} else {
return X(true, gcd(a.x, b.x));
}
},
(M a, X b) {
if (b.x == -1) {
return a;
} else if (!b.isGcd) {
return M(
b.x,
a.num,
a.num * b.x,
false,
b.x
);
} else {
if (!a.multiple) {
long x = gcd(a.maxValue, b.x);
return M(
x,
a.num,
a.num * x,
a.multiple,
x
);
} else if (a.lcmValue != -1 && b.x % a.lcmValue == 0) {
return a;
} else {
assert(a.num > 1);
return M(
a.maxValue,
a.num,
-1,
a.multiple,
1
);
}
}
},
M(-INF, 0, 0, false, 1),
X(false, -1)
)(as.map!(a => M(a, 1, a, false)).array);
foreach(i; 0..Q) {
long[] qs = readln.split.to!(long[]);
ref long q() { return qs[0]; }
ref long l() { return qs[1]; }
ref long r() { return qs[2]; }
ref long x() { return qs[3]; }
l--;
if (q == 1) {
seg.update(l, r, X(false, x));
} else if (q == 2) {
seg.update(l, r, X(true, x));
} else if (q == 3) {
seg.query(l, r).maxValue.writeln;
} else if (q == 4) {
seg.query(l, r).sumValue.writeln;
}
}
}
// // update(l, r, x) := as[l..r] += x
// // query(l, r) := as[l..r].sum
// struct P {
// long num, x;
// }
// alias RSQ = LazySegTree!(
// P, long,
// (a, b) => P(a.num + b.num, a.x + b.x),
// "a+b",
// (a, b) => P(a.num, a.x + b*a.num),
// P(0, 0),
// 0
// );
// Lazy Segment Tree
// - with 1-based array
struct LazySegTree(
M, // モノイドの型
X, // 作用素モノイドの型
alias funMM, // (M, M) → M : Mの2項演算
alias funXX, // (X, X) → X : Xの2項演算
alias funMX, // (M, X) → M : Xの元をMの元に作用させる関数
M eM, // Mの単位元
X eX, // Xの単位元
bool structly = true
) if (
is(typeof(binaryFun!funMM(eM, eM)) : M) &&
is(typeof(binaryFun!funXX(eX, eX)) : X) &&
is(typeof(binaryFun!funMX(eM, eX)) : M) &&
binaryFun!funMM(eM, eM) == eM &&
binaryFun!funXX(eX, eX) == eX &&
binaryFun!funMX(eM, eX) == eM
) {
private:
alias _funMM = binaryFun!funMM;
alias _funXX = binaryFun!funXX;
alias _funMX = binaryFun!funMX;
Pair[] _data;
X[] _lazy;
size_t _height;
size_t _size;
size_t _l, _r;
public:
// size: データ数
this(size_t size) {
init(size);
}
// 配列で指定
this(M[] ms) {
init(ms.length);
build(ms);
}
// O(N)
void init(size_t size){
_height = 0;
_size = 1;
while(_size < size) {
_size <<= 1;
_height++;
}
_data.length = _size<<1;
_lazy.length = _size<<1;
_data[] = Pair(size_t.max, eM);
_lazy[] = eX;
_l = 0;
_r = size;
}
// 区間 [a, b) を x ∈ X で作用
// O(logN)
void update(size_t a, size_t b, X x) {
assert(a <= b);
a += _size;
b += _size;
evaluate(a);
evaluate(b - 1);
for (size_t l = a, r = b; l < r; l >>= 1, r >>= 1) {
if (l&1) {
_lazy[l] = _funXX(_lazy[l], x);
l++;
}
if (r&1) {
r--;
_lazy[r] = _funXX(_lazy[r], x);
}
}
recalc(a);
recalc(b - 1);
}
// 区間[a, b)でのクエリ (valueの取得)
// O(logN)
M query(size_t a, size_t b) {
Pair pair = accumulate(a, b);
return pair.value;
}
// 区間[a, b)でのクエリ (indexの取得)
// O(logN)
size_t queryIndex(size_t a, size_t b) out(result) {
// fun == (a, b) => a+b のようなときはindexを聞くとassertion
if (structly) assert(result != size_t.max);
} body {
Pair pair = accumulate(a, b);
return pair.index;
}
// 区間[a, b)でのクエリ ((index, value)の取得)
// O(logN)
Pair queryPair(size_t a, size_t b) out(result) {
// fun == (a, b) => a+b のようなときはindexを聞くとassertion
if (structly) assert(result.index != size_t.max);
} body {
Pair pair = accumulate(a, b);
return pair;
}
// i番目の要素を取得
// O(logN)
M get(size_t i) {
i += _size;
evaluate(i);
return reflect(i).value;
}
// i番目の要素をmに更新
// O(logN)
void set(size_t i, M m) {
i += _size;
evaluate(i);
_data[i].value = m;
_lazy[i] = eX;
recalc(i);
}
private:
struct Pair {
size_t index;
M value;
}
Pair select(Pair nl, Pair nr) {
M v = _funMM(nl.value, nr.value);
if (nl.value == v) {
return nl;
} else if (nr.value == v) {
return nr;
} else {
return Pair(size_t.max, v);
}
}
Pair accumulate(size_t a, size_t b) {
assert(a <= b);
if (b<=_l || _r<=a) return Pair(size_t.max, eM);
a += _size;
b += _size;
evaluate(a);
evaluate(b - 1);
Pair accL = Pair(size_t.max, eM);
Pair accR = Pair(size_t.max, eM);
for (size_t l = a, r = b; l < r; l >>= 1, r >>= 1) {
if (l&1) accL = select(accL, reflect(l++));
if (r&1) accR = select(reflect(--r), accR);
}
return select(accL, accR);
}
// Pair reflect(size_t i) {
// if (_lazy[i] == eX) {
// return _data[i];
// } else {
// return Pair(
// _data[i].index,
// _funMX(_data[i].value, _lazy[i])
// );
// }
// }
Pair reflect(size_t i) {
if (_lazy[i] == eX) {
return _data[i];
} else {
Pair res = Pair(
_data[i].index,
_funMX(_data[i].value, _lazy[i])
);
if (res.value.sumValue == -1) {
thrust(i, false);
_data[i] = res = select(reflect(i<<1|0), reflect(i<<1|1));
}
return res;
}
}
void thrust(size_t i, bool shouldReflect = true) {
if (_lazy[i] == eX) return;
_lazy[i<<1|0] = _funXX(_lazy[i<<1|0], _lazy[i]);
_lazy[i<<1|1] = _funXX(_lazy[i<<1|1], _lazy[i]);
if (shouldReflect) _data[i] = reflect(i);
_lazy[i] = eX;
}
void evaluate(size_t i) {
foreach_reverse(k; 0.._height) {
thrust(i>>(k+1));
}
}
void recalc(size_t i) {
while(i > 0) {
i >>= 1;
_data[i] = select(reflect(i<<1|0), reflect(i<<1|1));
}
}
// O(N)
void build(M[] ms) {
foreach(i, e; ms) {
_data[i+_size] = Pair(i, e);
}
foreach_reverse(i; 1.._size) {
Pair nl = _data[i<<1|0];
Pair nr = _data[i<<1|1];
_data[i] = select(nl, nr);
}
}
}
// ----------------------------------------------
void times(alias fun)(long n) {
// n.iota.each!(i => fun());
foreach(i; 0..n) fun();
}
auto rep(alias fun, T = typeof(fun()))(long n) {
// return n.iota.map!(i => fun()).array;
T[] res = new T[n];
foreach(ref e; res) e = fun();
return res;
}
T ceil(T)(T x, T y) if (isIntegral!T || is(T == BigInt)) {
// `(x+y-1)/y` will only work for positive numbers ...
T t = x / y;
if (y > 0 && t * y < x) t++;
if (y < 0 && t * y > x) t++;
return t;
}
T floor(T)(T x, T y) if (isIntegral!T || is(T == BigInt)) {
T t = x / y;
if (y > 0 && t * y > x) t--;
if (y < 0 && t * y < x) t--;
return t;
}
ref T ch(alias fun, T, S...)(ref T lhs, S rhs) {
return lhs = fun(lhs, rhs);
}
unittest {
long x = 1000;
x.ch!min(2000);
assert(x == 1000);
x.ch!min(3, 2, 1);
assert(x == 1);
x.ch!max(100).ch!min(1000); // clamp
assert(x == 100);
x.ch!max(0).ch!min(10); // clamp
assert(x == 10);
}
mixin template Constructor() {
import std.traits : FieldNameTuple;
this(Args...)(Args args) {
// static foreach(i, v; args) {
foreach(i, v; args) {
mixin("this." ~ FieldNameTuple!(typeof(this))[i]) = v;
}
}
}
void scanln(Args...)(auto ref Args args) {
enum sep = " ";
enum n = Args.length;
enum fmt = n.rep!(()=>"%s").join(sep);
string line = readln.chomp;
static if (__VERSION__ >= 2074) {
line.formattedRead!fmt(args);
} else {
enum argsTemp = n.iota.map!(
i => "&args[%d]".format(i)
).join(", ");
mixin(
"line.formattedRead(fmt, " ~ argsTemp ~ ");"
);
}
}
// fold was added in D 2.071.0
static if (__VERSION__ < 2071) {
template fold(fun...) if (fun.length >= 1) {
auto fold(R, S...)(R r, S seed) {
static if (S.length < 2) {
return reduce!fun(seed, r);
} else {
return reduce!fun(tuple(seed), r);
}
}
}
}
// popcnt with ulongs was added in D 2.071.0
static if (__VERSION__ < 2071) {
ulong popcnt(ulong x) {
x = (x & 0x5555555555555555L) + (x>> 1 & 0x5555555555555555L);
x = (x & 0x3333333333333333L) + (x>> 2 & 0x3333333333333333L);
x = (x & 0x0f0f0f0f0f0f0f0fL) + (x>> 4 & 0x0f0f0f0f0f0f0f0fL);
x = (x & 0x00ff00ff00ff00ffL) + (x>> 8 & 0x00ff00ff00ff00ffL);
x = (x & 0x0000ffff0000ffffL) + (x>>16 & 0x0000ffff0000ffffL);
x = (x & 0x00000000ffffffffL) + (x>>32 & 0x00000000ffffffffL);
return x;
}
}