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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

ICPC 南昌现场赛 K:Tree(dsu on tree + 动态开点线段树)

發(fā)布時間:2023/12/4 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ICPC 南昌现场赛 K:Tree(dsu on tree + 动态开点线段树) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Tree

讓我們找滿足一下五個條件的(x,y(x, y(x,y)點對有多少:

  • x≠yx \neq yx?=y
  • xxx不是yyy的祖先
  • yyy不是xxx的祖先
  • dis(x,y)≤kdis(x, y)\leq kdis(x,y)k
  • zzzx,yx, yx,y的最近公共祖先,valuex+valuey=2valuezvalue_x + value_y = 2value_zvaluex?+valuey?=2valuez?

讀題目觀察到每個節(jié)點的valuevaluevalue只有[0,105][0, 10 ^ 5][0,105](如果不是的話,也可離散化處理一下吧),所以我們可以建立10510 ^ 5105棵線段樹,每棵線段樹里面記錄的是點權(quán)為iii的節(jié)點的深度信息,

所以我們只要做一次dsuontreedsu\ on\ treedsu?on?tree,動態(tài)維護這顆線段樹,然后按照需要查詢即可,好像并不是特別難。

#include <bits/stdc++.h>using namespace std;const int N = 2e5 + 10;int head[N], to[N], nex[N], cnt = 1;int value[N], n, m;int son[N], sz[N], dep[N], l[N], r[N], rk[N], tot;int root[N], ls[N << 6], rs[N << 6], sum[N << 6], num;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[son[rt]] < sz[to[i]]) {son[rt] = to[i];}}r[rt] = tot; }void push_up(int rt) {sum[rt] = sum[ls[rt]] + sum[rs[rt]]; }void update(int &rt, int l, int r, int x, int value) {if (!rt) {rt = ++num;}if (l == r) {sum[rt] += value;return ;}int mid = l + r >> 1;if (x <= mid) {update(ls[rt], l, mid, x, value);}else {update(rs[rt], mid + 1, r, x, value);}push_up(rt); }int query(int rt, int l, int r, int L, int R) {if (!rt) {return 0;}if (l >= L && r <= R) {return sum[rt];}int mid = l + r >> 1, ans = 0;if (L <= mid) {ans += query(ls[rt], l, mid, L, R);}if (R > mid) {ans += query(rs[rt], mid + 1, r, L, R);}return ans; }long long ans;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);}int v = 2 * value[rt], d = dep[rt];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++) {int target_v = v - value[rk[j]], last_d = m - (dep[rk[j]] - d);//目標(biāo)權(quán)值,剩下的可延展的距離if (target_v < 0 || last_d <= 0) {//如果目標(biāo)權(quán)值小于0或者剩下的可延展距離沒有了,提前剪除不合法continue;}int l = d + 1, r = d + last_d;//深度的區(qū)間范圍,然后查詢即可。ans += query(root[target_v], 1, n, l, r);}for (int j = l[to[i]]; j <= r[to[i]]; j++) {update(root[value[rk[j]]], 1, n, dep[rk[j]], 1);}}update(root[value[rt]], 1, n, dep[rt], 1);if (!keep) {for (int i = l[rt]; i <= r[rt]; i++) {update(root[value[rk[i]]], 1, n, dep[rk[i]], -1);}} }int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);scanf("%d %d", &n, &m);for (int i = 1; i <= n; i++) {scanf("%d", &value[i]);}for (int i = 2; i <= n; i++) {int x;scanf("%d", &x);add(x, i);}dfs(1, 0);dfs(1, 0, 1);printf("%lld\n", ans * 2);return 0; }

總結(jié)

以上是生活随笔為你收集整理的ICPC 南昌现场赛 K:Tree(dsu on tree + 动态开点线段树)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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