D1T1 code
簽到題,大家都會。
可以從高位往低位確定,如果遇到 \(1\),則將排名取反一下。
注意要開 unsigned long long。
#include <bits/stdc++.h>
typedef unsigned long long u64;
const int MaxN = 100;
u64 n, K;
bool ans[MaxN];
inline void solve(u64 dep, u64 k)
{
if (dep == 0)
return;
u64 lsze = 1ull << (dep - 1);
if (k < lsze)
{
ans[dep] = false;
solve(dep - 1, k);
}
else
{
ans[dep] = true;
solve(dep - 1, lsze - (k - lsze) - 1);
}
}
int main()
{
freopen("code.in", "r", stdin);
freopen("code.out", "w", stdout);
std::cin >> n >> K;
solve(n, K);
for (int i = n; i >= 1; --i)
putchar(ans[i] ? '1' : '0');
return 0;
}
D1T2 brackets
簡單題,大家都會。
大家的做法都好巨,我只會奇奇怪怪的做法。
考慮每次加一個括號之后答案的增量,顯然只有加右括號的時候答案會增加。
我們記兩個量, \(lst\_lef_i\) 表示 \(i\to 1\) 的路徑上最后一個沒有匹配的左括號,\(lst\_blk_i\) 表示以 \(i\) 結尾的合法子串個數(本質上是數出類似這種串 ...(...)(...)(...)(...) 的極長合法后綴可以分成幾段 (...))。
這兩個量可以直接線性推出來,然后就做完了。時間復雜度 \(O(n)\)。
#include <bits/stdc++.h>
template <class T>
inline void read(T &x)
{
static char ch;
while (!isdigit(ch = getchar()));
x = ch - '0';
while (isdigit(ch = getchar()))
x = x * 10 + ch - '0';
}
typedef long long s64;
const int MaxNV = 5e5 + 5;
const int MaxNE = MaxNV;
int n;
int fa[MaxNV];
char s[MaxNV];
int lst_lef[MaxNV];
int lst_blk[MaxNV];
s64 ans[MaxNV], xor_ans;
int main()
{
freopen("brackets.in", "r", stdin);
freopen("brackets.out", "w", stdout);
scanf("%d%s", &n, s + 1);
for (int i = 2; i <= n; ++i)
read(fa[i]);
if (s[1] == '(')
lst_lef[1] = 1;
for (int u = 2; u <= n; ++u)
{
ans[u] = ans[fa[u]];
if (s[u] == '(')
{
lst_lef[u] = u;
lst_blk[u] = 0;
}
else
{
if (lst_lef[fa[u]])
{
int lef_u = lst_lef[fa[u]];
lst_lef[u] = lst_lef[fa[lef_u]];
lst_blk[u] = lst_blk[fa[lef_u]] + 1;
ans[u] += lst_blk[u];
}
else
{
lst_lef[u] = 0;
lst_blk[u] = 0;
}
}
xor_ans ^= 1LL * u * ans[u];
}
std::cout << xor_ans << std::endl;
return 0;
}
D1T3 tree
細節題。這個題的 idea 挺好的,就是容易分類討論掛。
難度其實不大,放在 D1T3 其實沒啥毛病。可能出題人高估了我的代碼能力。我太菜了,考場上調不出來。
一個顯然的貪心就是從小到大枚舉數字,然后判斷這個數字最終能送到那個位置。顯然每次我們都貪心地選取最小的位置。
考慮一條路徑 \(u_1\to u_2\to \dots \to u_k\),假設我們要將 \(u_1\) 的原來數字送到 \(u_k\),那么需要滿足下列條件:
- \((u_1,u_2)\) 是和 \(u_1\) 相連的所有邊中第一個被刪除的。
- \((u_{k - 1}, u_k)\) 是和 \(u_k\) 相連的所有邊中最后一個被刪除的。
- \((u_{i-1},u_i)\) 必須比 \((u_i,u_{i+1})\) 先刪除,並且在刪除 \((u_{i-1},u_i)\) 后,刪除 \((u_i,u_{i+1})\) 之前,不能有和 \(u_i\) 相連的其他邊被刪除。
那么我們就對每個點,維護出與其相連的所有邊的限制。這些限制具體可以用一個鏈表來表示,並且需要記錄每個點強制限制的第一個刪除的邊,和最后一個刪除的邊。
實現的時候,就從當前枚舉的數字所在的點開始 dfs,顯然滿足第一個和第三個條件的點構成一個聯通塊。我們只需要在 dfs 的時候順帶判斷這些條件能否滿足即可。
時間復雜度 \(O(n^2)\)。細節比較多,我是根據考場的混亂思路瞎寫的,相信讀者一定有比我更優秀的實現方法。
#include <bits/stdc++.h>
template <class T>
inline void read(T &x)
{
static char ch;
while (!isdigit(ch = getchar()));
x = ch - '0';
while (isdigit(ch = getchar()))
x = x * 10 + ch - '0';
}
template <class T>
inline void putint(T x)
{
static char buf[25], *tail = buf;
if (!x)
putchar('0');
else
{
for (; x; x /= 10) *++tail = x % 10 + '0';
for (; tail != buf; --tail) putchar(*tail);
}
}
const int MaxN = 2e3 + 5;
int n;
int idx[MaxN], col[MaxN], fa[MaxN];
int adj[MaxN][MaxN], deg[MaxN];
int ans[MaxN];
int fir[MaxN], lst[MaxN];
int head[MaxN][MaxN], sze[MaxN][MaxN];
int pre[MaxN][MaxN], suf[MaxN][MaxN];
inline void init()
{
read(n);
for (int i = 1; i <= n; ++i)
{
fir[i] = lst[i] = 0;
deg[i] = ans[i] = fa[i] = 0;
for (int j = 1; j <= n; ++j)
{
head[i][j] = j;
sze[i][j] = 1;
pre[i][j] = suf[i][j] = 0;
}
}
for (int i = 1; i <= n; ++i)
{
read(idx[i]);
col[idx[i]] = i;
}
for (int i = 1; i < n; ++i)
{
int u, v;
read(u), read(v);
adj[u][++deg[u]] = v;
adj[v][++deg[v]] = u;
}
}
inline void dfs(int u, int src)
{
if (u != src)
{
bool flg = true;
if (deg[u] != 1)
{
flg &= fir[u] != fa[u] && !suf[u][fa[u]];
flg &= !lst[u] || lst[u] == fa[u];
if (fir[u] && head[u][fir[u]] == head[u][fa[u]])
flg &= sze[u][head[u][fa[u]]] == deg[u];
}
if (flg)
{
if (!ans[src] || u < ans[src])
ans[src] = u;
}
}
for (int i = 1; i <= deg[u]; ++i)
{
int v = adj[u][i];
if (v == fa[u])
continue;
fa[v] = u;
bool flg = true;
if (u == src)
{
if (deg[u] != 1)
{
flg &= lst[u] != v && !pre[u][v];
if (lst[u] && head[u][lst[u]] == head[u][v])
flg &= sze[u][head[u][v]] == deg[u];
}
}
else
{
flg &= !suf[u][fa[u]] || suf[u][fa[u]] == v;
flg &= !pre[u][v] || pre[u][v] == fa[u];
flg &= suf[u][fa[u]] == v || head[u][v] != head[u][fa[u]];
flg &= head[u][fir[u]] != head[u][v] && head[u][lst[u]] != head[u][fa[u]];
if (head[u][lst[u]] == head[u][v] && head[u][fir[u]] == head[u][fa[u]])
flg &= sze[u][head[u][lst[u]]] + sze[u][head[u][fir[u]]] == deg[u];
}
if (flg)
dfs(v, src);
}
}
inline void modify(int x, int src)
{
if (!x)
return;
lst[x] = fa[x];
int y = x;
while (fa[y] != src)
{
suf[fa[y]][fa[fa[y]]] = y;
pre[fa[y]][y] = fa[fa[y]];
if (head[fa[y]][fa[fa[y]]] != head[fa[y]][y])
{
int l = head[fa[y]][fa[fa[y]]];
int z = y;
while (z)
{
++sze[fa[y]][l];
head[fa[y]][z] = l;
z = suf[fa[y]][z];
}
}
y = fa[y];
}
fir[src] = y;
}
inline void solve()
{
for (int c = 1; c <= n; ++c)
{
int u = idx[c];
if (n == 1)
{
puts("1");
continue;
}
fa[u] = 0;
dfs(u, u);
modify(ans[u], u);
putint(ans[u]);
putchar(" \n"[c == n]);
}
}
int main()
{
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
int orzczk;
read(orzczk);
while (orzczk--)
{
init();
solve();
}
return 0;
}
D2T1 meal
簡單題,就我不會。考場上降智太嚴重了,會了 \(O(mn^3)\) 竟然不會 \(O(mn^2)\)。我校其他選手全部 AC 此題,水平高下立判。
因為如果有食材超過一半,那么最多只能有一個這樣的食材,所以不難想到用總的方案數減去有一個主要食材超過一半的方案數。總的方案數就是
減一是因為不能一個都不選。
考慮如何限制某個食材超過一半,顯然我們可以考慮枚舉這個食材,然后把用這個食材的菜權值看成 \(+1\),不用這個食材的菜權值看成 \(-1\),那么相當於選的所有菜的總權值要大於 \(0\)。
具體地,我們可以用一個背包 DP 實現。顯然大家都會,就不講了。
記 \(f(i,j)\) 表示前 \(i\) 種方法,選的菜的總權值為 \(j\) 的方案數。
假設現在限制的是第 \(p\) 種食材,那么轉移非常顯然:
為了避免負數下標,可以加一個常數。時間復雜度 \(O(mn^2)\)。
#include <bits/stdc++.h>
template <class T>
inline void read(T &x)
{
static char ch;
while (!isdigit(ch = getchar()));
x = ch - '0';
while (isdigit(ch = getchar()))
x = x * 10 + ch - '0';
}
const int MaxN = 1e2 + 5;
const int MaxM = 2e3 + 5;
const int mod = 998244353;
int n, m;
int a[MaxN][MaxM], sum[MaxN];
int f[MaxN][MaxN << 1];
inline void add(int &x, const int &y)
{
x += y;
if (x >= mod)
x -= mod;
}
inline void dec(int &x, const int &y)
{
x -= y;
if (x < 0)
x += mod;
}
inline int minus(int x, const int &y)
{
x -= y;
return x < 0 ? x + mod : x;
}
int main()
{
freopen("meal.in", "r", stdin);
freopen("meal.out", "w", stdout);
read(n), read(m);
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= m; ++j)
{
read(a[i][j]);
add(sum[i], a[i][j]);
}
}
int ans = 1;
for (int i = 1; i <= n; ++i)
ans = 1LL * ans * (sum[i] + 1) % mod;
dec(ans, 1);
for (int p = 1; p <= m; ++p)
{
f[0][n] = 1;
for (int i = 1; i <= n; ++i)
for (int j = 0; j <= (n << 1); ++j)
{
f[i][j] = f[i - 1][j];
if (j > 0)
add(f[i][j], 1LL * f[i - 1][j - 1] * a[i][p] % mod);
if (j < (n << 1))
add(f[i][j], 1LL * f[i - 1][j + 1] * minus(sum[i], a[i][p]) % mod);
}
for (int i = 1; i <= n; ++i)
dec(ans, f[n][i + n]);
}
printf("%d\n", ans);
return 0;
}
D2T2 partition
打表找規律題,考場上來不及了。
開始我們有一個顯然的 DP 是,設 \(f(i,j)\) 表示前 \(i\) 個數,最后一段是 \([j+1,i]\),的最小平方和。這樣的 DP 實現地優秀一點可以做到 \(O(n^2)\)。
強烈的感覺告訴我們,這題有奇妙結論,考場上當然是打表。打表后不難發現在合法范圍內,\(f(i,j)\) 隨 \(j\) 單調遞減。
結論的證明參考出題人myy的博客: http://matthew99.blog.uoj.ac/blog/5299
簡單總結一下這個證明:
結論: 把所有解的斷點從大到小寫下來,然后剩下的位置補0,那么最優解對應的序列在所有位置都是最大值。(不難發現,這個定義使最優解唯一)
證明: 結論等價於,對於每個解,從后往前將每一段的和寫出來,然后補無限個零,得到一個對應的序列,那么最優解對應的序列任意位置的前綴和都是最小的。
假設這個對應從后往前寫出的每一段和的序列為 \(\{b_i\}\),考慮另一個解對應的序列 \(\{c_i\}\),顯然不會出現某個位置 \(k\) 的前綴和 \(\sum_{i=1}^kb_i > \sum_{i=1}^kc_i\),否則就會和最優解的定義矛盾。
因此現在需要證明的就是對於任意一個滿足
\[\forall k, \sum_{i=1}^kb_i\leq \sum_{i=1}^kc_i \]的解對應序列 \(c\)(\(c\) 和 \(b\) 不同),都有
\[\sum_{i=1}^{+\infty}b_i^2 < \sum_{i=1}^{+\infty}c_i^2 \]證明的思路是,將序列 \(c\) 經過一些使平方和減小的調整,並且使得任意時刻都滿足所有位置的前綴和不小於 \(b\),最后讓 \(c\) 變成 \(b\)。這樣就能證明 \(c\) 的平方和不小於 \(b\) 的。(注意調整的含義是直接對 \(c\) 進行修改,在調整過程中沒有必要保證 \(c\) 存在對應的原序列中的解,我們只關心 \(c\) 和 \(b\) 平方和的大小關系)
注意到對於一個單調不增的序列 \(a\),若 \(i<j\) 且 \(a_i>a_{i+1},a_{j-1}>a_j, a_i-a_j\geq 2\),將 \(a_i\) 減一,\(a_j\) 加一,可以使 \(a\) 仍然單調不增,並且平方和減小。
找到第一個滿足 \(c_u>b_u\) 的位置 \(u\),在 \(u\) 的后面一定能找到第一個位置 \(v\) 滿足 \(c_v<b_v\)(因為 \(c\) 和 \(b\) 所有元素的總和一樣)。因為 \(c\) 和 \(b\) 都單調不增,所以 \(c_u-c_v\geq 2\),即區間 \([u,v]\) 的權值跨度至少為 \(2\)。找到最小的滿足 \(i\geq u,c_{i}>c_{i+1}\) 的位置 \(i\),找到最大的滿足 \(j\leq v,c_{j-1}>c_j\) 的位置 \(j\),那么 \(u\leq i<j\leq v\),並且 \(c_i-c_j\geq 2\)。於是將 \(c_i\) 減一,\(c_j\) 加一,可以使 \(c\) 仍然遞增,並且平方和減小,不難發現,這么操作仍然保證了 \(c\) 的每個位置的前綴和不小於 \(b\) 的。
於是不斷這么操作,一定能使 \(c\) 最終變成 \(b\),而在操作過程中平方和不斷減小,於是原來的 \(c\) 的平方和是大於 \(b\) 的。\(\square\)
因此我們對於每個 \(i\) 只要記一個最優決策點即可,每個 \(i\) 的決策點一定是取在最靠右的合法位置。記這個位置為 \(p_i\)。考慮一個決策點 \(j(j<i)\) 是合法的當且僅當 \(s_i-s_j\geq s_j-s_{p_j}\),其中 \(s_i\) 表示 \(1\dots i\) 的前綴和。
移項一下這個條件就是 \(2s_j-s_{p_j} \leq s_i\),到這里可以用一個BIT 做到 \(O(n \log n)\)。
但是實際上,不難發現 \(s_i\) 是單增的,也就是說一個決策點 \(j\) 對於當前的 \(i\) 是合法的,那么對於后面的肯定仍是合法的。於是我們考慮維護一個\(2s_j-s_{p_j}\) 單增的單調隊列。對於每個 \(i\) 就從隊頭開始找到最后一個合法決策點,再將 \(i\) 插到隊尾,並且將隊尾的那些 \(2s_j-s_{p_j}\geq 2s_i-s_{p_i}\) 的決策點彈掉。這樣的時間復雜度就是 \(O(n)\) 了。
本題還有個問題就是,你不能一邊做這個 DP 一邊算這個 DP 值,得把 \(p_i\) 存起來最后算(因為空間不夠)。高精還需要壓位/二進制。當然,你在 OJ 上用 __int128 也是可以的。
#include <bits/stdc++.h>
template <class T>
inline void read(T &x)
{
static char ch;
static bool opt;
while (!isdigit(ch = getchar()) && ch != '-');
x = (opt = ch == '-') ? 0 : ch - '0';
while (isdigit(ch = getchar()))
x = x * 10 + ch - '0';
if (opt)
x = ~x + 1;
}
template <class T>
inline void putint(T x)
{
static char buf[45], *tail = buf;
if (!x)
putchar('0');
else
{
if (x < 0)
{
putchar('-');
x = ~x + 1;
}
for (; x; x /= 10) *++tail = x % 10 + '0';
for (; tail != buf; --tail) putchar(*tail);
}
}
typedef long long s64;
const int MaxN = 4e7 + 5;
const s64 mod = 1e9;
int n, type, ql, qr;
int que[MaxN], maxp[MaxN], b[MaxN];
s64 s[MaxN];
struct bignum
{
int len;
s64 a[7];
bignum(){}
bignum(s64 t)
{
len = 1;
memset(a, 0, sizeof(a));
a[1] = t % mod;
if (t >= mod)
a[++len] = t / mod;
}
inline void operator += (const bignum &rhs)
{
len = std::max(len, rhs.len);
for (int i = 1; i <= len; ++i)
{
a[i] += rhs.a[i];
a[i + 1] += a[i] / mod;
a[i] %= mod;
}
if (a[len + 1])
++len;
}
inline bignum operator * (const bignum &rhs) const
{
bignum res(0);
res.len = len + rhs.len;
for (int i = 1; i <= len; ++i)
for (int j = 1; j <= rhs.len; ++j)
res.a[i + j - 1] += a[i] * rhs.a[j];
for (int i = 1; i < res.len; ++i)
{
res.a[i + 1] += res.a[i] / mod;
res.a[i] %= mod;
}
while (res.len > 1 && !res.a[res.len])
--res.len;
return res;
}
inline void print()
{
printf("%d", (int)a[len]);
for (int i = len - 1; i >= 1; --i)
printf("%09d", (int)a[i]);
}
}res(0);
inline s64 calc(int x)
{
return 2 * s[x] - s[maxp[x]];
}
int main()
{
freopen("partition.in", "r", stdin);
freopen("partition.out", "w", stdout);
read(n), read(type);
if (type == 0)
{
for (int i = 1; i <= n; ++i)
{
int x;
read(x);
s[i] = s[i - 1] + x;
}
}
else
{
int x, y, z, m;
read(x), read(y), read(z), read(b[1]), read(b[2]), read(m);
for (int i = 1, lstp = 0; i <= m; ++i)
{
int p, l, r;
read(p), read(l), read(r);
for (int j = lstp + 1; j <= p; ++j)
{
if (j > 2)
b[j] = (1LL * x * b[j - 1] + 1LL * y * b[j - 2] + z) % (1 << 30);
s[j] = s[j - 1] + b[j] % (r - l + 1) + l;
}
lstp = p;
}
}
que[ql = qr = 1] = 0;
for (int i = 1; i <= n; ++i)
{
while (ql < qr && calc(que[ql + 1]) <= s[i])
++ql;
maxp[i] = que[ql];
while (ql <= qr && calc(que[qr]) >= calc(i))
--qr;
que[++qr] = i;
}
int cur = n;
while (cur)
{
res += bignum(s[cur] - s[maxp[cur]]) * bignum(s[cur] - s[maxp[cur]]);
cur = maxp[cur];
}
res.print();
return 0;
}
D2T3 centroid
不難題,就我不會。因為這是 D2T3 所以我只想着寫暴力,實際上這題挺簡單的。
將題目中的計算方式轉化為:對於每個點,計算它成為重心的方案數。
那么考慮一個點 \(u\),將其硬點為根,對於它的每個兒子 \(v\),相當於在 \(v\) 的子樹再選出一個大小為 \(s_0\) 的子樹,這個 \(s_0\) 需要在一個范圍。具體地,我們記 \(s'\) 表示 \(u\) 除了 \(v\) 以外的其他兒子的最大子樹大小,記 \(s_v\) 表示 \(v\) 的子樹大小。
那么就有
以及
那么就要求 \(s_0\in [2s_v-n,n-2s^\prime]\)。
對應到原樹(欽定 \(1\) 為根的有根樹)上,這相當於分兩類討論:
- \(v\) 是 \(u\) 的一個兒子,這個時候直接在 dfs 時用一個 BIT 存下當前結點到根的路徑上所有點的詢問區間對應的貢獻,然后遍歷到一個點的時候在 BIT 上單點查詢即可。
- \(v\) 是 \(u\) 的父親,這時候的統計比較復雜,需要分成幾塊統計:
- 原樹中不在 \(u\) 子樹中且不在 \(u\) 到根路徑上的結點的 \(size\in [2(n-s_u)-n,n-2s^\prime]\),這個可以用整棵樹中 \(size\) 在這個區間的點數減去子樹內 \(size\) 在這個區間的點數,再減去到根結點的路徑上的點 \(size\) 在這個區間的點數。子樹詢問可以歸到第一類的 BIT 中,到根結點的可以另外再維護一個 BIT。
- 原樹中 \(u\) 到根的路徑上,向父親方向的「子樹」。這個可以 dfs 的時候歸到上面第二個 BIT 維護。
那么這樣我們就可以用 BIT 來做了。時間復雜度 \(O(n\log n)\),常數有點大,可能打不過線段樹選手。
(補充:我太菜了,其實那些詢問看成二維數點然后離線 BIT 就可以了,不用我這么麻煩,但是這樣常數好像也很大)
#include <bits/stdc++.h>
template <class T>
inline void read(T &x)
{
static char ch;
while (!isdigit(ch = getchar()));
x = ch - '0';
while (isdigit(ch = getchar()))
x = x * 10 + ch - '0';
}
template <class T>
inline void putint(T x)
{
static char buf[25], *tail = buf;
if (!x)
putchar('0');
else
{
for (; x; x /= 10) *++tail = x % 10 + '0';
for (; tail != buf; --tail) putchar(*tail);
}
}
template <class T>
inline void relax(T &x, const T &y)
{
if (x < y)
x = y;
}
template <class T>
inline void tense(T &x, const T &y)
{
if (x > y)
x = y;
}
typedef long long s64;
const int MaxNV = 3e5 + 5;
const int MaxNE = MaxNV << 1;
int n;
int ect, adj[MaxNV];
int nxt[MaxNE], to[MaxNE];
int fa[MaxNV], sze[MaxNV];
s64 ans, sum[MaxNV], bit_q[MaxNV], bit_u[MaxNV];
int max_sze[MaxNV][2];
#define trav(u) for (int e = adj[u], v; v = to[e], e; e = nxt[e])
inline void addEdge(int u, int v)
{
nxt[++ect] = adj[u];
adj[u] = ect;
to[ect] = v;
}
inline void init()
{
read(n);
ect = 0;
ans = 0;
for (int i = 1; i <= n; ++i)
{
adj[i] = sum[i] = 0;
bit_q[i] = bit_u[i] = 0;
max_sze[i][0] = max_sze[i][1] = 0;
}
for (int i = 1; i < n; ++i)
{
int u, v;
read(u), read(v);
addEdge(u, v);
addEdge(v, u);
}
}
inline void bit_modify(int x, int val, s64 *bit)
{
for (; x <= n; x += x & -x)
bit[x] += val;
}
inline s64 bit_query(int x, s64 *bit)
{
s64 res = 0;
for (; x; x ^= x & -x)
res += bit[x];
return res;
}
inline void seg_modify(int l, int r, int val, s64 *bit)
{
relax(l, 1), tense(r, n);
if (r < l) return;
bit_modify(l, val, bit);
bit_modify(r + 1, -val, bit);
}
inline s64 seg_query(int l, int r, s64 *bit)
{
relax(l, 1), tense(r, n);
if (r < l) return 0;
return bit_query(r, bit) - bit_query(l - 1, bit);
}
inline void upt(int x, int s)
{
if (s >= max_sze[x][0])
{
max_sze[x][1] = max_sze[x][0];
max_sze[x][0] = s;
}
else
relax(max_sze[x][1], s);
}
inline int max_else(int x, int s)
{
if (s == max_sze[x][0])
return max_sze[x][1];
return max_sze[x][0];
}
inline void dfs_init(int u)
{
sze[u] = 1;
trav(u)
if (v != fa[u])
{
fa[v] = u;
dfs_init(v);
sze[u] += sze[v];
upt(u, sze[v]);
}
upt(u, n - sze[u]);
}
inline void dfs(int u)
{
int ul = std::max(1, 2 * (n - sze[u]) - n);
int ur = std::min(n, n - 2 * max_else(u, n - sze[u]));
if (ul <= ur)
ans += (sum[ur] - sum[ul - 1]) * u;
seg_modify(ul, ur, -u, bit_q);
ans += bit_query(sze[u], bit_q);
ans += seg_query(ul, ur, bit_u) * u;
trav(u)
if (v != fa[u])
{
int t_s = max_else(u, sze[v]);
int l = 2 * sze[v] - n, r = n - 2 * t_s;
seg_modify(l, r, u, bit_q);
bit_modify(sze[u], -1, bit_u);
bit_modify(n - sze[v], 1, bit_u);
dfs(v);
seg_modify(l, r, -u, bit_q);
bit_modify(sze[u], 1, bit_u);
bit_modify(n - sze[v], -1, bit_u);
}
seg_modify(ul, ur, u, bit_q);
}
inline void solve()
{
dfs_init(1);
for (int i = 1; i <= n; ++i)
++sum[sze[i]];
for (int i = 1; i <= n; ++i)
sum[i] += sum[i - 1];
dfs(1);
putint(ans);
putchar('\n');
}
int main()
{
freopen("centroid.in", "r", stdin);
freopen("centroid.out", "w", stdout);
int orzczk;
read(orzczk);
while (orzczk--)
{
init();
solve();
}
return 0;
}
