「NOIP2016」天天爱跑步

知识点: 树上差分,线段树合并

原题面 Loj Luogu


之前口嗨的时候说自己可以用线段树合并过去然后发现自己并不会做硬刚了很长时间终于刚了出来但是思路奇特实现复杂把代码写的奇丑无比自己看见都会吐而且在写题解之前还扯这么一大堆madan上面这一堆话已经差不多到了一百字了再不停下来就会被当成傻逼的 Luckyblock 是人间之屑。


题意简述

gu


分析题意


爆零小技巧


代码实现

写的奇丑,没有任何参考价值。
建议自行 yy。

//知识点:树上差分,线段树合并 
/*
By:Luckyblock
*/
#include <cstdio>
#include <ctype.h>
#include <cstring>
#include <algorithm>
#define ll long long
#define ls (lson[now_])
#define rs (rson[now_])
const int kMaxn = 3e5 + 10;
const int kInf = 5e5 + 10;
//=============================================================
int edge_num, w[kMaxn], head[kMaxn], v[kMaxn << 1], ne[kMaxn << 1];
int n, m, delta, node_num, root[kMaxn], lson[kMaxn << 6], rson[kMaxn << 6], sum[kMaxn << 6];
int dep[kMaxn], fa[kMaxn][22];
int qu[kMaxn], qv[kMaxn], lca[kMaxn], ans[kMaxn];
//=============================================================
inline int read() {
  int f = 1, w = 0; char ch = getchar();
  for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
  return f * w;
}
void GetMax(int &fir, int sec) {
  if (sec > fir) fir = sec;
}
void GetMin(int &fir, int sec) {
  if (sec < fir) fir = sec;
}
void AddEdge(int u_, int v_) {
  v[++ edge_num] = v_; ne[edge_num] = head[u_], head[u_] = edge_num;
}
void Dfs1(int u_, int fat_) {
  fa[u_][0] = fat_;
  dep[u_] = dep[fat_] + 1;
  for (int i = 1; i < 20; ++ i) {
    fa[u_][i] = fa[fa[u_][i - 1]][i - 1];
  }
  for (int i = head[u_]; i; i = ne[i]) {
    int v_ = v[i];
    if (v_ == fat_) continue ;
    Dfs1(v_, u_);
  }
}
int GetLca(int x_, int y_, bool flag_) {
  bool flag_swap = false;
  if (dep[x_] < dep[y_]) {
    std :: swap(x_, y_); 
    flag_swap = true;
  }
  for (int i = 20; i >= 0; -- i) {
    if (dep[fa[x_][i]] > dep[y_]) {
      x_ = fa[x_][i];
    }
  }
  if (fa[x_][0] == y_) return flag_ ? x_ : y_;
  if (dep[x_] > dep[y_]) x_ = fa[x_][0];
  for (int i = 20; i >= 0; -- i) {
    if (fa[x_][i] != fa[y_][i]) {
      x_ = fa[x_][i], y_ = fa[y_][i];
    }
  }
  if (flag_swap) return flag_ ? y_ : fa[y_][0];
  return flag_ ? x_ : fa[x_][0];
}
void Clear(int now_) {
  ls = rs = sum[now_] = 0;
}
void Update(int now_) {
  sum[now_] = sum[ls] + sum[rs];
}
void Insert(int &now_, int L_, int R_, int pos_, int val_) {
  if (! now_) {
    now_ = ++ node_num;
    Clear(node_num);
  }
  if (L_ == R_) {
    sum[now_] += val_;
    return ;
  }
  int mid = (L_ + R_) >> 1;
  if (pos_ <= mid) Insert(ls, L_, mid, pos_, val_);
  else Insert(rs, mid + 1, R_, pos_, val_);
  Update(now_);
}
int Merge(int now_, int y_, int L_, int R_) {
  if (! now_ || ! y_) return now_ + y_;
  if (L_ == R_) {
    sum[now_] += sum[y_];
    return now_;
  }
  int mid = (L_ + R_) >> 1;
  ls = Merge(ls, lson[y_], L_, mid);
  rs = Merge(rs, rson[y_], mid + 1, R_);
  Update(now_);
  return now_;
}
int Query(int now_, int L_, int R_, int pos_) {
  if (L_ == R_ || ! sum[now_]) return sum[now_];
  int mid = (L_ + R_) >> 1;
  if (pos_ <= mid) return Query(ls, L_, mid, pos_);
  else return Query(rs, mid + 1, R_, pos_);
}
void Dfs(int u_, bool flag_) {
  for (int i = head[u_]; i; i = ne[i]) {
    int v_ = v[i];
    if (v_ == fa[u_][0]) continue ;
    Dfs(v_, flag_);
    root[u_] = Merge(root[u_], root[v_], 1, kInf);
  }
  if (! flag_) ans[u_] += Query(root[u_], 1, kInf, dep[u_] + w[u_]);
  if (flag_) ans[u_] += Query(root[u_], 1, kInf, dep[u_] - w[u_] + delta);
}
//=============================================================
int main() {
  delta = n = read(), m = read();
  for (int i = 1; i < n; ++ i) {
    int u = read(), v = read();
    AddEdge(u, v), AddEdge(v, u);
  }
  Dfs1(1, 0);
  for (int i = 1; i <= n; ++ i) w[i] = read();
  for (int i = 1; i <= m; ++ i) {
    qu[i] = read(), qv[i] = read(), lca[i] = GetLca(qu[i], qv[i], true);
    if (qu[i] == qv[i]) {
      Insert(root[qu[i]], 1, kInf, dep[qu[i]], 1);
      if (fa[qu[i]][0]) Insert(root[fa[qu[i]][0]], 1, kInf, dep[qu[i]], - 1);
      continue ;
    }
    if (qu[i] == fa[lca[i]][0]) continue ;
    Insert(root[qu[i]], 1, kInf, dep[qu[i]], 1);
    if (fa[lca[i]][0] == qv[i]) {
      if (fa[lca[i]][1]) Insert(root[fa[lca[i]][1]], 1, kInf, dep[qu[i]], - 1);
      continue ; 
    }
    if (fa[lca[i]][0]) Insert(root[fa[lca[i]][0]], 1, kInf, dep[qu[i]], - 1);
  }
  Dfs(1, false);
  node_num = 0;
  memset(root, 0, sizeof (root));
  for (int i = 1; i <= m; ++ i) {
    lca[i] = fa[lca[i]][0];
    if (qv[i] == lca[i] || qu[i] == qv[i]) continue ;
    Insert(root[qv[i]], 1, kInf, 2 * dep[lca[i]] - dep[qu[i]] + delta, 1);
    if (fa[lca[i]][0]) Insert(root[fa[lca[i]][0]], 1, kInf, 2 * dep[lca[i]] - dep[qu[i]] + delta, - 1);
  }
  Dfs(1, true);
  for (int i = 1; i <= n; ++ i) printf("%d ", ans[i]);
  return 0;
}
上一篇:luogu P2831 [NOIP2016 提高组] 愤怒的小鸟


下一篇:[ 备战NOIP2016 ] 斐波那契数列