日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

小 Q 与树(dsu on tree + segment tree)牛客练习赛 81 D

發(fā)布時(shí)間:2023/12/4 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 小 Q 与树(dsu on tree + segment tree)牛客练习赛 81 D 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

小 Q 與樹(shù)

給定一棵帶權(quán)的樹(shù),每條邊的距離都為111,要我們求∑u=1n∑v=1nmin(au,av)dis(u,v)\sum\limits_{u = 1} ^{n} \sum\limits_{v = 1} ^{n}min(a_u, a_v)dis(u, v)u=1n?v=1n?min(au?,av?)dis(u,v)
min(au,av)dis(u,v)=min(au,av)(dep[u]+dep[v]?2×dep[lca(u,v)])min(a_u, a_v) dis(u, v) = min(a_u, a_v)\left(dep[u] + dep[v] - 2 \times dep[lca(u, v)]\right)\\ min(au?,av?)dis(u,v)=min(au?,av?)(dep[u]+dep[v]?2×dep[lca(u,v)])

如果考慮 dsu on tree,則是枚舉uuu,分兩種情況統(tǒng)計(jì)答案:

  • au≤ava_u \leq a_vau?av?,則∑v∈Sau(dep[u]+dep[v]?2×dep[lca(u,v)])\sum\limits_{v \in S} a_u(dep[u] + dep[v] - 2 \times dep[lca(u, v)])vS?au?(dep[u]+dep[v]?2×dep[lca(u,v)]),則我們只要知道集合SSS中有多少個(gè)點(diǎn),以及∑v∈Sdep[v]\sum\limits_{v \in S} dep[v]vS?dep[v]即可,

    設(shè)點(diǎn)的個(gè)數(shù)為totaltotaltotal∑v∈Sdep[v]=Sumdep\sum\limits_{v \in S} dep[v] = Sum_{dep}vS?dep[v]=Sumdep?,則上式等價(jià)于au×tatal×(dep[u]?2×dep[lca(u,v)])+au×Sumdepa_u \times tatal \times (dep[u] - 2 \times dep[lca(u, v)]) + a_u \times Sum_{dep}au?×tatal×(dep[u]?2×dep[lca(u,v)])+au?×Sumdep?。

  • au>ava_u > a_vau?>av?,則∑u∈Sav(dep[u]+dep[v]?2×dep[lca(u,v)])\sum\limits_{u \in S} a_v(dep[u] + dep[v] - 2 \times dep[lca(u, v)])uS?av?(dep[u]+dep[v]?2×dep[lca(u,v)]),則我們只要知道Sumav×dep[v]Sum_{a_v \times dep[v]}Sumav?×dep[v]?,以及SumavSum_{a_v}Sumav??即可求得答案,

    上式等價(jià)于Sumav×dep[v]+Sumav×(dep[u]?2×dep[lca(u,v)])Sum_{a_v \times dep[v]} + Sum_{a_v} \times (dep[u] - 2 \times dep[lca(u, v)])Sumav?×dep[v]?+Sumav??×(dep[u]?2×dep[lca(u,v)])

所以可以對(duì)點(diǎn)權(quán)離散化,然后用線段樹(shù)來(lái)維護(hù)上面需要的四個(gè)值,即可進(jìn)行 dsu on tree,整體復(fù)雜度nlog?nlog?nn \log n \log nnlognlogn。

由于上面的統(tǒng)計(jì)我們都是進(jìn)行的單向計(jì)算,所以還要對(duì)上述計(jì)算完后的答案乘以222即可。

#include <bits/stdc++.h> #define ls rt << 1 #define rs rt << 1 | 1 #define mid (l + r >> 1) #define lson ls, l, mid #define rson rs, mid + 1, rusing namespace std;const int N = 2e5 + 10, mod = 998244353;int head[N], to[N << 1], nex[N << 1], cnt = 1;int son[N], sz[N], l[N], r[N], rk[N], dep[N], tot;int sum1[N << 2], sum2[N << 2], sum3[N << 2], sum4[N << 2];int a[N], b[N], n, m;inline int add(int x, int y) {return x + y < mod ? x + y : x + y - mod; }inline int sub(int x, int y) {return x >= y ? x - y : x - y + mod; }inline int mul(int x, int y) {return 1ll * x * y % mod; }void Add(int x, int y) {to[cnt] = y;nex[cnt] = head[x];head[x] = cnt++; }void dfs(int rt, int fa) {dep[rt] = dep[fa] + 1, sz[rt] = 1, l[rt] = ++tot, rk[tot] = rt;for (int i = head[rt]; i; i = nex[i]) {if (to[i] == fa) {continue;}dfs(to[i], rt);sz[rt] += sz[to[i]];if (!son[rt] || sz[to[i]] > sz[son[rt]]) {son[rt] = to[i];}}r[rt] = tot; }void push_up(int rt) {sum1[rt] = add(sum1[ls], sum1[rs]);sum2[rt] = add(sum2[ls], sum2[rs]);sum3[rt] = add(sum3[ls], sum3[rs]);sum4[rt] = add(sum4[ls], sum4[rs]); }void update(int rt, int l, int r, int x, int v, int op) {if (l == r) {if (op == 1) {sum1[rt] += 1, sum2[rt] = add(sum2[rt], v), sum3[rt] = add(sum3[rt], mul(b[x], v)), sum4[rt] = add(sum4[rt], b[x]);}else {sum1[rt] -= 1, sum2[rt] = sub(sum2[rt], v), sum3[rt] = sub(sum3[rt], mul(b[x], v)), sum4[rt] = sub(sum4[rt], b[x]);}return ;}if (x <= mid) {update(lson, x, v, op);}else {update(rson, x, v, op);}push_up(rt); }int ans, ans1, ans2, ans3, ans4, ans5;void query(int rt, int l, int r, int L, int R) {if (l >= L && r <= R) {ans1 = add(ans1, sum1[rt]), ans2 = add(ans2, sum2[rt]), ans3 = add(ans3, sum3[rt]), ans4 = add(ans4, sum4[rt]);return ;}if (L <= mid) {query(lson, L, R);}if (R > mid) {query(rson, L, R);} }void dfs(int rt, int fa, bool keep) {for (int i = head[rt]; i; i = nex[i]) {if (to[i] == fa || to[i] == son[rt]) {continue;}dfs(to[i], rt, 0);}if (son[rt]) {dfs(son[rt], rt, 1);}for (int i = head[rt]; i; i = nex[i]) {if (to[i] == fa || to[i] == son[rt]) {continue;}for (int j = l[to[i]]; j <= r[to[i]]; j++) {ans1 = ans2 = ans3 = ans4 = 0;query(1, 1, m, a[rk[j]], m);ans = add(ans, mul(ans2, b[a[rk[j]]]));ans = add(ans, mul(b[a[rk[j]]], mul(ans1, sub(dep[rk[j]], 2 * dep[rt]))));if (a[rk[j]] != 1) {ans1 = ans2 = ans3 = ans4 = 0;query(1, 1, m, 1, a[rk[j]] - 1);ans = add(ans, ans3);ans = add(ans, mul(ans4, sub(dep[rk[j]], 2 * dep[rt])));}}for (int j = l[to[i]]; j <= r[to[i]]; j++) {update(1, 1, m, a[rk[j]], dep[rk[j]], 1);}}ans1 = ans2 = ans3 = ans4 = 0;query(1, 1, m, a[rt], m);ans = add(ans, mul(ans2, b[a[rt]]));ans = add(ans, mul(b[a[rt]], mul(ans1, sub(dep[rt], 2 * dep[rt]))));if (a[rt] != 1) {ans1 = ans2 = ans3 = ans4 = 0;query(1, 1, m, 1, a[rt] - 1);ans = add(ans, ans3);ans = add(ans, mul(ans4, sub(dep[rt], 2 * dep[rt])));}update(1, 1, m, a[rt], dep[rt], 1);if (!keep) {for (int i = l[rt]; i <= r[rt]; i++) {update(1, 1, m, a[rk[i]], dep[rk[i]], -1);}} }int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);scanf("%d", &n);for (int i = 1; i <= n; i++) {scanf("%d", &a[i]);b[i] = a[i];}sort(b + 1, b + 1 + n);m = unique(b + 1, b + 1 + n) - (b + 1);for (int i = 1; i <= n; i++) {a[i] = lower_bound(b + 1, b + 1 + m, a[i]) - b;}for (int i = 1, x, y; i < n; i++) {scanf("%d %d", &x, &y);Add(x, y);Add(y, x);}dfs(1, 0);dfs(1, 0, 1);printf("%d\n", mul(2, ans));return 0; }

總結(jié)

以上是生活随笔為你收集整理的小 Q 与树(dsu on tree + segment tree)牛客练习赛 81 D的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。