結果
| 問題 |
No.235 めぐるはめぐる (5)
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2017-07-19 14:33:14 |
| 言語 | D (dmd 2.109.1) |
| 結果 |
CE
(最新)
AC
(最初)
|
| 実行時間 | - |
| コード長 | 8,242 bytes |
| コンパイル時間 | 577 ms |
| コンパイル使用メモリ | 145,044 KB |
| 最終ジャッジ日時 | 2024-11-14 20:07:34 |
| 合計ジャッジ時間 | 1,616 ms |
|
ジャッジサーバーID (参考情報) |
judge4 / judge5 |
(要ログイン)
コンパイルエラー時のメッセージ・ソースコードは、提出者また管理者しか表示できないようにしております。(リジャッジ後のコンパイルエラーは公開されます)
ただし、clay言語の場合は開発者のデバッグのため、公開されます。
ただし、clay言語の場合は開発者のデバッグのため、公開されます。
コンパイルメッセージ
/home/linuxbrew/.linuxbrew/opt/dmd/include/dlang/dmd/std/format/internal/write.d(143): Error: cannot implicitly convert expression `obj` of type `const(FactorRing!(1000000007, false))` to `int` /home/linuxbrew/.linuxbrew/opt/dmd/include/dlang/dmd/std/format/write.d(1239): Error: template instance `std.format.internal.write.formatValueImpl!(LockingTextWriter, FactorRing!(1000000007, false), char)` error instantiating /home/linuxbrew/.linuxbrew/opt/dmd/include/dlang/dmd/std/format/write.d(632): instantiated from here: `formatValue!(LockingTextWriter, FactorRing!(1000000007, false), char)` /home/linuxbrew/.linuxbrew/opt/dmd/include/dlang/dmd/std/stdio.d(1759): instantiated from here: `formattedWrite!(LockingTextWriter, char, FactorRing!(1000000007, false))` /home/linuxbrew/.linuxbrew/opt/dmd/include/dlang/dmd/std/stdio.d(4277): instantiated from here: `write!(FactorRing!(1000000007, false), char)` Main.d(103): instantiated from here: `writeln!(FactorRing!(1000000007, false))`
ソースコード
import std.algorithm, std.conv, std.range, std.stdio, std.string;
const mod = 10 ^^ 9 + 7;
alias FactorRing!mod mint;
alias SegmentTreeLazy!(mint, mint(0), "a + b") segtree;
alias CulSum!mint culSum;
void main()
{
auto n = readln.chomp.to!size_t;
auto s = new mint[](n), c = new mint[](n);
auto rds = readln.chomp.splitter, rdc = readln.chomp.splitter;
foreach (i; 0..n) {
s[i] = rds.front.to!int; rds.popFront();
c[i] = rdc.front.to!int; rdc.popFront();
}
auto tree = Tree(n);
foreach (_; 0..n-1) {
auto rd = readln.split.to!(size_t[]), a = rd[0]-1, b = rd[1]-1;
tree.addEdge(a, b);
}
tree.rootify(0);
tree.makePath(0);
auto np = tree.paths.length;
auto css = new culSum*[](np), csc = new culSum*[](np);
auto stl = new segtree*[](np);
foreach (i; 0..np) {
css[i] = new culSum(s.indexed(tree.paths[i]).array);
csc[i] = new culSum(c.indexed(tree.paths[i]).array);
auto npi = tree.paths[i].length;
stl[i] = new segtree(npi);
stl[i].weight = *csc[i];
}
auto q = readln.chomp.to!size_t;
foreach (_; 0..q) {
auto rd = readln.chomp.splitter;
auto km = rd.front.to!int; rd.popFront();
auto x = rd.front.to!size_t-1; rd.popFront();
auto y = rd.front.to!size_t-1; rd.popFront();
auto lca = tree.lca(x, y);
if (y == lca) swap(x, y);
auto calc0(size_t u, size_t v, int z, bool includeU) {
while (tree.path[u] != tree.path[v]) {
auto d = tree.depthInPath(v);
auto p = tree.path[v];
(*stl[p])[0..d+1] += mint(z);
v = tree.parent[tree.head[v]];
}
auto d1 = tree.depthInPath(u), d2 = tree.depthInPath(v);
auto p = tree.path[u];
if (includeU)
(*stl[p])[d1..d2+1] += mint(z);
else if (d1 < d2)
(*stl[p])[d1+1..d2+1] += mint(z);
}
auto calc1(size_t u, size_t v, bool includeU) {
auto r = mint(0);
while (tree.path[u] != tree.path[v]) {
auto d = tree.depthInPath(v);
auto p = tree.path[v];
r += (*stl[p])[0..d+1] + (*css[p])[0..d+1];
v = tree.parent[tree.head[v]];
}
auto d1 = tree.depthInPath(u), d2 = tree.depthInPath(v);
auto p = tree.path[u];
if (includeU)
r += (*stl[p])[d1..d2+1] + (*css[p])[d1..d2+1];
else if (d1 < d2)
r += (*stl[p])[d1+1..d2+1] + (*css[p])[d1+1..d2+1];
return r;
}
switch (km) {
case 0:
auto z = rd.front.to!int;
if (x == lca) {
calc0(x, y, z, true);
} else {
calc0(lca, x, z, true);
calc0(lca, y, z, false);
}
break;
case 1:
auto r = mint(0);
if (x == lca) {
r += calc1(x, y, true);
} else {
r += calc1(lca, x, true);
r += calc1(lca, y, false);
}
writeln(r);
break;
default:
assert(0);
}
}
}
struct CulSum(T)
{
T[] buf;
this(T[] a)
{
buf = new T[](a.length + 1);
buf[1..$][] = a[];
foreach (i; 0..a.length)
buf[i+1] += buf[i];
}
T opSlice(size_t l, size_t r)
{
return buf[r] - buf[l];
}
}
struct SegmentTreeLazy(T, T unit, alias pred = "a + b")
{
import core.bitop, std.conv, std.functional, std.range;
alias predFun = binaryFun!pred;
enum Op { none, add };
const size_t n, an;
T[] buf, laz;
Op[] op;
CulSum!mint weight;
this(size_t n)
{
this.n = n;
an = (1 << ((n - 1).bsr + 1));
buf = new T[](an * 2);
laz = new T[](an * 2);
op = new Op[](an * 2);
static if (T.init != unit) {
buf[] = unit;
}
}
void propagate(size_t k, size_t nl, size_t nr)
{
if (op[k] == Op.none) return;
size_t nm = (nl + nr) / 2;
setLazy(op[k], laz[k], k*2, nl, nm);
setLazy(op[k], laz[k], k*2+1, nm, nr);
op[k] = Op.none;
}
void setLazy(Op nop, T val, size_t k, size_t nl, size_t nr)
{
switch (nop) {
case Op.add:
buf[k] += val * weight[nl..nr];
laz[k] = op[k] == Op.none ? val : laz[k] + val;
op[k] = Op.add;
break;
default:
assert(0);
}
}
void addOpe(Op op, T val, size_t l, size_t r, size_t k, size_t nl, size_t nr)
{
if (nr <= l || r <= nl) return;
if (l <= nl && nr <= r) {
setLazy(op, val, k, nl, nr);
return;
}
propagate(k, nl, nr);
auto nm = (nl + nr) / 2;
addOpe(op, val, l, r, k*2, nl, nm);
addOpe(op, val, l, r, k*2+1, nm, nr);
buf[k] = predFun(buf[k*2], buf[k*2+1]);
}
void opSliceOpAssign(string op: "+")(T val, size_t l, size_t r)
{
addOpe(Op.add, val, l, r, 1, 0, an);
}
T summary(size_t l, size_t r, size_t k, size_t nl, size_t nr)
{
if (nr <= l || r <= nl) return unit;
if (l <= nl && nr <= r) return buf[k];
propagate(k, nl, nr);
auto nm = (nl + nr) / 2;
auto vl = summary(l, r, k*2, nl, nm);
auto vr = summary(l, r, k*2+1, nm, nr);
return predFun(vl, vr);
}
T opSlice(size_t l, size_t r)
{
return summary(l, r, 1, 0, an);
}
pure size_t opDollar() const { return n; }
}
struct Tree
{
import std.container;
size_t n;
size_t[][] adj;
int[] size, depth;
size_t[] head, parent, path;
size_t[][] paths;
this(size_t n)
{
this.n = n;
adj = new size_t[][](n);
}
auto addEdge(size_t s, size_t t)
{
adj[s] ~= t;
adj[t] ~= s;
}
auto rootify(size_t r)
{
parent = new size_t[](n);
depth = new int[](n);
depth[] = -1;
struct UP { size_t u, p; }
auto st1 = SList!UP(UP(r, r));
auto st2 = SList!UP();
while (!st1.empty) {
auto up = st1.front, u = up.u, p = up.p; st1.removeFront();
parent[u] = p;
depth[u] = depth[p] + 1;
foreach (v; adj[u])
if (v != p) {
st1.insertFront(UP(v, u));
st2.insertFront(UP(v, u));
}
}
size = new int[](n);
size[] = 1;
while (!st2.empty) {
auto up = st2.front, u = up.u, p = up.p; st2.removeFront();
size[p] += size[u];
}
head = new size_t[](n);
head[] = n;
struct US { size_t u, s; }
auto st = SList!US(US(r, r));
while (!st.empty) {
auto us = st.front, u = us.u, s = us.s; st.removeFront();
head[u] = s;
auto z = n;
foreach (v; adj[u])
if (head[v] == n && (z == n || size[z] < size[v])) z = v;
foreach (v; adj[u])
if (head[v] == n) st.insertFront(US(v, v == z ? s : v));
}
}
auto makePath(size_t r)
{
auto pathIndex = 0;
path = new size_t[](n);
auto q = DList!size_t(r);
while (!q.empty) {
auto u = q.front; q.removeFront();
if (u == head[u]) {
path[u] = pathIndex++;
paths ~= [u];
} else {
path[u] = path[head[u]];
paths[path[u]] ~= u;
}
foreach (v; adj[u])
if (v != parent[u]) q.insertBack(v);
}
}
auto depthInPath(size_t n)
{
return depth[n] - depth[head[n]];
}
auto lca(size_t u, size_t v)
{
while (head[u] != head[v])
if (depth[head[u]] < depth[head[v]]) v = parent[head[v]];
else u = parent[head[u]];
return depth[u] < depth[v] ? u : v;
}
}
struct FactorRing(int m, bool pos = false)
{
long v;
@property int toInt() { return v.to!int; }
alias toInt this;
this(T)(T _v) { v = mod(_v); }
ref FactorRing!(m, pos) opAssign(int _v)
{
v = mod(_v);
return this;
}
pure auto mod(long _v) const
{
static if (pos) return _v % m;
else return (_v % m + m) % m;
}
pure auto opBinary(string op: "+")(long rhs) const { return FactorRing!(m, pos)(v + rhs); }
pure auto opBinary(string op: "-")(long rhs) const { return FactorRing!(m, pos)(v - rhs); }
pure auto opBinary(string op: "*")(long rhs) const { return FactorRing!(m, pos)(v * rhs); }
pure auto opBinary(string op)(FactorRing!(m, pos) rhs) const
if (op == "+" || op == "-" || op == "*") { return opBinary!op(rhs.v); }
auto opOpAssign(string op: "+")(long rhs) { v = mod(v + rhs); }
auto opOpAssign(string op: "-")(long rhs) { v = mod(v - rhs); }
auto opOpAssign(string op: "*")(long rhs) { v = mod(v * rhs); }
auto opOpAssign(string op)(FactorRing!(m, pos) rhs)
if (op == "+" || op == "-" || op == "*") { return opOpAssign!op(rhs.v); }
}