码迷,mamicode.com
首页 > 其他好文 > 详细

uoj435 Simple Tree

时间:2020-03-01 00:02:04      阅读:70      评论:0      收藏:0      [点我收藏+]

标签:mod   处理   getch   register   区间查询   turn   修改   space   max   

原题链接

这显然是一道树据结构毒瘤卡常

考虑用树剖

则原操作珂转换为:

  1. 在区间\([l, r]\)同时\(±1\)
  2. 询问区间\([l, r]\)内有多少数\(>0\)

然后发现不能线段树

珂以用分块

在每一块里搞一个关于值域的后缀和,即\(\text{cnt}_{\text{i,j}}\)表示在第\(\text i\)块里大于或等于\(\text j\)的个数。

这珂以利用后缀和预处理出来。

因为每一次只是\(±1\),所以每一次在\(\text{cnt}\)上修改是\(O(1)\)

区间修改时,整个块打\(\text{lazy}\)标记,旁边的暴力修改。

区间查询时,整个块里询问有多少个数\(>-\text{lazy}_\text i\),旁边的暴力查询。

所以总时间复杂度\(O(n^{1.5}\log n)\)

贴一下代码(太卡常了):

// by H~$~C
#include <stdio.h>
static int _swaptmp;
#define swap(x, y) (_swaptmp = x, x = y, y = _swaptmp) // 卡常毒瘤 

#ifndef LOCAL_JUDGE
static char _in_buf[100000], *_in_p1 = _in_buf, *_in_p2 = _in_buf;
#define gc (__builtin_expect(_in_p1 == _in_p2, 0) && (_in_p2 = (_in_p1 = _in_buf) +         fread(_in_buf, 1, 100000, stdin), _in_p1 == _in_p2) ? -1 : *_in_p1++)
#else
#define gc getchar()
#endif
inline int read() {
  register char ch = gc;
  register int x = 0, flag = 0;
  while ((ch < 48 || ch > 57) && ch != 45) ch = gc;
  if (ch == 45) flag = 1, ch = gc;
  while (ch > 47 && ch < 58) x = (x << 3) + (x << 1) + (ch ^ 48), ch = gc;
  return flag ? -x : x;
} // 继续卡常 

static const int Maxn = 100005;

int n, q, opt_type, lastans;
int a[Maxn], b[Maxn];
struct Edge {
  int to, nxt;
} e[Maxn << 1];
int head[Maxn], tot_edge;
inline void add_edge(int u, int v) {
  e[++tot_edge] = (Edge){v, head[u]};
  head[u] = tot_edge;
}

int son[Maxn], sz[Maxn];
int par[Maxn], dep[Maxn];
int top[Maxn], ind[Maxn], indx;
void dfs1(int u, int parent, int depth) {
  par[u] = parent;
  dep[u] = depth;
  sz[u] = 1;
  for (register int i = head[u]; i; i = e[i].nxt) {
    int v = e[i].to;
    if (v == parent) continue;
    dfs1(v, u, depth + 1);
    sz[u] += sz[v];
    if (sz[son[u]] < sz[v])
      son[u] = v;
  }
}
void dfs2(int u, int topv) {
  top[u] = topv;
  ind[u] = ++indx;
  a[indx] = b[u];
  if (son[u]) dfs2(son[u], topv);
  for (register int i = head[u]; i; i = e[i].nxt)
    if (e[i].to != par[u] && e[i].to != son[u])
      dfs2(e[i].to, e[i].to);
}

namespace BLOCK {
  static const int BASE = ::Maxn;
  static const int blk = 248; // 调参珂真好 
  static const int BLOCK_SIZE = ::Maxn / blk + 5;
  int bl[Maxn];
  int L[Maxn], R[Maxn];
  int lazy[Maxn];
  unsigned char suf[BLOCK_SIZE][Maxn << 1]; // 还是卡常 
  void build() {
    register int i, j;
    for (i = 1; i <= n; ++i) {
      bl[i] = (i - 1) / blk + 1;
      if (!L[bl[i]]) L[bl[i]] = i;
      R[bl[i]] = i;
    }
    for (i = 1; i <= bl[n]; ++i) {
      for (j = L[i]; j <= R[i]; ++j) {
        suf[i][a[j] + BASE]++;
      }
      for (j = BASE * 2; j >= 0; --j) {
        suf[i][j] += suf[i][j + 1];
      }
    }
  }
  inline void add(int b, int &x, int val) {
    if (val == 1) {
      ++x;
      ++suf[b][x + BASE];
    }
    else {
      --suf[b][x + BASE];
      --x;
    }
  }
  void modify(int l, int r, int val) {
    int pl = bl[l], pr = bl[r];
    register int i;
    if (pl == pr) {
      for (i = l; i <= r; ++i)
        add(pl, a[i], val);
      return ; 
    }
    for (i = l; i <= R[pl]; ++i)
      add(pl, a[i], val);
    for (i = L[pr]; i <= r; ++i)
      add(pr, a[i], val);
    for (i = pl + 1; i < pr; ++i)
      lazy[i] += val;
  }
  int query(int l, int r) {
    int pl = bl[l], pr = bl[r];
    int ans = 0;
    register int i;
    if (pl == pr) {
      for (i = l; i <= r; ++i)
        ans += (a[i] + lazy[pl] > 0);
      return ans;
    }
    for (i = l; i <= R[pl]; ++i) {
      ans += (a[i] + lazy[pl] > 0);
    }
    for (i = L[pr]; i <= r; ++i) {
      ans += (a[i] + lazy[pr] > 0);
    }
    for (i = pl + 1; i < pr; ++i) {
      ans += suf[i][BASE - lazy[i] + 1];
    }
    return ans;
  }
}

inline void modify(int x, int y, int w) {
  while (top[x] != top[y]) {
    if (dep[top[x]] < dep[top[y]]) swap(x, y);
    BLOCK::modify(ind[top[x]], ind[x], w);
    x = par[top[x]];
  }
  if (dep[x] > dep[y]) swap(x, y);
  BLOCK::modify(ind[x], ind[y], w);
}
inline int query(int x, int y) {
  int res = 0;
  while (top[x] != top[y]) {
    if (dep[top[x]] < dep[top[y]]) swap(x, y);
    res += BLOCK::query(ind[top[x]], ind[x]);
    x = par[top[x]];
  }
  if (dep[x] > dep[y]) swap(x, y);
  res += BLOCK::query(ind[x], ind[y]);
  return res;
}

int main() {
  register int i;
  n = read(), q = read(), opt_type = read();
  for (i = 1; i < n; ++i) {
    int u = read(), v = read();
    add_edge(u, v);
    add_edge(v, u);
  }
  for (i = 1; i <= n; ++i) {
    b[i] = read();
// 如果原数太大(>q)或太小(<-q),则符号不会改变 
    if (b[i] > 100002) b[i] = 100002;
    if (b[i] < -100002) b[i] = -100002;
  }
  dfs1(1, 0, 1);
  dfs2(1, 1);
  BLOCK::build();
  while (q--) {
    int op = read();
    int x = read(), y, w;
    if (opt_type) x ^= lastans;
    if (op == 1) {
      y = read();
      w = read();
      if (opt_type) y ^= lastans;
      modify(x, y, w);
    }
    else if (op == 2) {
      y = read();
      if (opt_type) y ^= lastans;
      lastans = query(x, y);
      printf("%d\n", lastans);
    }
    else {
      lastans = BLOCK::query(ind[x], ind[x] + sz[x] - 1);
      printf("%d\n", lastans);
    }
  }
  return 0;
}

uoj435 Simple Tree

标签:mod   处理   getch   register   区间查询   turn   修改   space   max   

原文地址:https://www.cnblogs.com/libra9z/p/12387326.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!