# LOJ#2473. 「九省联考 2018」秘密袭击（线段树合并+拉格朗日插值）

f[i][j][k] represents the subtree of the node i and we are considering the value of the kth node is not less than j. This block already has k nodes which have value not less than j.

#include <bits/stdc++.h>
using namespace std;

typedef unsigned int ui;

const int N = 2e3 + 5;
const int M = N * 2;
const ui mod = 64123;
const int MAX = 1e5 + 5;

struct NODE {
ui a, b, c, d;
friend NODE operator * (NODE er, NODE la) {
return
(NODE) {er.a * la.a % mod, (la.a * er.b % mod + la.b) % mod
, (la.c * er.a % mod + er.c) % mod,
(er.b * la.c % mod + la.d + er.d) % mod};
}
void init() {
a = 1; b = c = d = 0;
}
}T[MAX];

int n, k, W, d[N], fir[N], ne[M], to[M], cnt, rt[N], sz, ch[MAX][2];

#define lc (ch[x][0])
#define rc (ch[x][1])

void add(int x, int y) {
ne[++ cnt] = fir[x];
fir[x] = cnt;
to[cnt] = y;
}

void link(int x, int y) {
}

#define Foreachson(i, x) for(int i = fir[x]; i; i = ne[i])

int x, y;
scanf("%d%d%d", &n, &k, &W);
for(int i = 1; i <= n; ++ i) scanf("%d", &d[i]);
for(int i = 1; i < n; ++ i) {
scanf("%d%d", &x, &y);
}
}

ui poly[N], F[MAX], S[MAX];

int newnode() {
++ sz;
F[sz] = S[sz] = 0;
T[sz].init();
ch[sz][0] = ch[sz][1] = 0;
return sz;
}

void pt(int &x, NODE who) {
if(!x) x = newnode();
T[x] = T[x] * who;
return;
}

void pd(int x) {
pt(lc, T[x]);
pt(rc, T[x]);
T[x].init();
}

void chg(int &x, int l, int r, int L, int R, NODE who) {
if(!x) x = newnode();
if(l == L && r == R) {
T[x] = T[x] * who;
return;
}
pd(x);
int mid = (l + r) >> 1;
if(L > mid) chg(rc, mid + 1, r, L, R, who);
else if(R <= mid) chg(lc, l, mid, L, R, who);
else chg(lc, l, mid, L, mid, who), chg(rc, mid + 1, r, mid + 1, R, who);
}

int merge(int x, int y) {
if(!x || !y) return x + y;
if(!ch[x][0] && !ch[x][1]) swap(x, y);
if(!ch[y][0] && !ch[y][1]) {
// y's is ((a + b), d)
T[x].a = T[x].a * T[y].b % mod;
T[x].b = T[x].b * T[y].b % mod;
T[x].d = (T[x].d + T[y].d) % mod;
return x;
}
pd(x); pd(y);
ch[x][0] = merge(ch[x][0], ch[y][0]);
ch[x][1] = merge(ch[x][1], ch[y][1]);
return x;
}

void dfs(int x, int f, ui magic) {
rt[x] = newnode();
pt(rt[x], (NODE){0, 1, 0, 0});
Foreachson(i, x) {
int V = to[i];
if(V == f) continue;
dfs(V, x, magic);
rt[x] = merge(rt[x], rt[V]);
}
if(d[x]) chg(rt[x], 1, W, 1, d[x], (NODE){magic, 0, 0, 0});
pt(rt[x], (NODE){1, 0, 1, 0});
pt(rt[x], (NODE){1, 1, 0, 0});
}

void query(int &x, int l, int r, ui &ans) {
if(l == r) {
ans = ans + (T[x].d);
ans %= mod;
return;
}
int mid = (l + r) >> 1;
pd(x);
query(lc, l, mid, ans), query(rc, mid + 1, r, ans);
}

ui f[N], g[N];

int Pow(ui x, int y) {
ui res = 1;
for(; y; y >>= 1, x = 1LL * x * x % mod) {
if(y & 1) {
res = 1LL * res * x % mod;
}
}
return res;
}

void dec(ui *f, ui *g, int x) {
for(int i = 0; i <= n + 1; ++ i) g[i] = f[i];
ui Inv = Pow(x, mod - 2);
for(int i = 0; i <= n; ++ i) {
g[i] = 1LL * g[i] * (mod - Inv) % mod;
g[i + 1] = (g[i + 1] - g[i] + mod) % mod;
}
assert(!g[n + 1]);
}

void Lagrange(void) {
memset(f, 0, sizeof(f));
memset(g, 0, sizeof(g));
f[0] = 1;
for(int i = 1; i <= n + 1; ++ i)
for(int j = n + 1; j >= 0; -- j)
f[j + 1] = (f[j + 1] + f[j]) % mod,
f[j] = 1LL * f[j] * (mod - i) % mod;
ui ans = 0;
for(int i = 1; i <= n + 1; ++ i) {
dec(f, g, i);
ui now = 0;
for(int j = k; j <= n; ++ j) now = (now + g[j]) % mod;
for(int j = 1; j <= n + 1; ++ j) {
if(i != j)
now = now * Pow((i - j + mod) % mod, mod - 2) % mod;
}
now = now * poly[i] % mod;
ans = (ans + now) % mod;
}
cout << ans << endl;
}

int main() {