E. Party Company

容易发现这是一颗树形结构,根节点为 1 1 1,并且有点权从根节点开始递减。

题目大意就是给定一个点 u , l , r u, l, r u,l,r,对于于 u u u在同一个连通块里,并且点权是在 [ l , r ] [l, r] [l,r]之间的点答案贡献加一。

如果理解到上述的题意,那这题就变得简单了。

由于我们要求的是在同一个联通块里的,并且点权具有单调性,我们可以通过二分跳转到可以满足的深度最小的节点上去,在这个节点依附上 l l l

容易想到,满足要求的点一定是出现在这个节点的子树上的,所以我们可以动态维护一个以 l l l的有序数组,然后在每个节点二分查找,有多少个值是小于等于当前节点的,这个值就是当前节点的答案了。

当我们退出这颗子树的时候,记得清空这个节点上依附的 l l l

由于 l , r l, r l,r都比较小,所以可以直接通过树状数组,进行单点修改,前缀和查询,整体复杂度 O ( n log ⁡ m + m log ⁡ m ) O(n \log m + m \log m) O(nlogm+mlogm)

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int head[N], to[N], nex[N], cnt = 1;

int fa[N], son[N], sz[N], top[N], rk[N], id[N], dep[N], tot;

int n, m, value[N], ans[N];

vector<int> vt[N];

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

void dfs1(int rt, int f) {
  fa[rt] = f, sz[rt] = 1, dep[rt] = dep[f] + 1;
  for (int i = head[rt]; i; i = nex[i]) {
    if (to[i] == f) {
      continue;
    }
    dfs1(to[i], rt);
    sz[rt] += sz[to[i]];
    if (!son[rt] || sz[to[i]] > sz[son[rt]]) {
      son[rt] = to[i];
    }
  }
}

void dfs2(int rt, int tp) {
  top[rt] = tp, rk[++tot] = rt, id[rt] = tot;
  if (!son[rt]) {
    return ;
  }
  dfs2(son[rt], tp);
  for (int i = head[rt]; i; i = nex[i]) {
    if (to[i] == fa[rt] || to[i] == son[rt]) {
      continue;
    }
    dfs2(to[i], to[i]);
  }
}

void solve(int cur, int L, int R) {
  while (cur != 1) {
    if (fa[top[cur]] && value[fa[top[cur]]] <= R) {
      cur = fa[top[cur]];
    }
    else {
      int l = id[top[cur]], r = id[cur];
      while (l < r) {
        int mid = l + r >> 1;
        if (value[rk[mid]] > R) {
          l = mid + 1;
        }
        else {
          r = mid;
        }
      }
      vt[rk[l]].push_back(L);
      return ;
    }
  }
  vt[1].push_back(L);
}

int tree[N];

int lowbit(int x) {
  return x & (-x);
}

void update(int x, int value) {
  while (x < N) {
    tree[x] += value;
    x += lowbit(x);
  }
}

int query(int x) {
  int ans = 0;
  while (x) {
    ans += tree[x];
    x -= lowbit(x);
  }
  return ans;
}

void dfs(int rt, int fa) {
  for (auto it : vt[rt]) {
    update(it, 1);
  }
  ans[rt] = query(value[rt]);
  for (int i = head[rt]; i; i = nex[i]) {
    if (to[i] == fa) {
      continue;
    }
    dfs(to[i], rt);
  }
  for (auto it : vt[rt]) {
    update(it, -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, fa; i <= n; i++) {
    scanf("%d %d", &value[i], &fa);
    if (i != 1) {
      add(fa, i);
    }
  }
  dfs1(1, 0);
  dfs2(1, 1);
  for (int i = 1; i <= m; i++) {
    int cur, l, r;
    scanf("%d %d %d", &cur, &l, &r);
    solve(cur, l, r);
  }
  dfs(1, 0);
  for (int i = 1; i <= n; i++) {
    printf("%d%c", ans[i], i == n ? '\n' : ' ');
  }
  return 0;
}