• uoj435 Simple Tree


    原题链接

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

    考虑用树剖

    则原操作珂转换为:

    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;
    }
    
  • 相关阅读:
    TCP协议中粘包现象
    python 中socket模块及用法
    网络编程之五层协议
    面向对象的反射和双下方法(魔术方法)
    Centos下的redis安装和使用
    面向对象简介
    supervisor进程管理工具
    redis的持久化
    redis的主从同步及哨兵的用法
    ubuntu修改grub默认启动项
  • 原文地址:https://www.cnblogs.com/libra9z/p/12387326.html
Copyright © 2020-2023  润新知