伪TopTree(AAA Tree) BZOJ3153

主要思想来自Claris的博客.

开始搞很久之前的一个flag。

这种数据结构也算Top Tree的范畴,但是好多人似乎更愿意叫她AAA树。

LCT是不能做子树的,当前的Splay只能维护重链上的信息。

那么我们不妨把虚儿子也装到一颗Splay里。

由于虚儿子不存在父子关系关系,我们需要让虚儿子都是Splay的叶子,这时需要引入内部点来占位。

新增的两项操作是Add和Del,也就是添加虚边和删除虚边,必要时添加内部点和删除内部点。

这样在Access操作引发的变化就是,把原来的x挂到父亲右儿子的操作变为:断开自己虚边,添加父亲原右儿子的虚边,连自己和父亲右儿子的实边。

Link操作就加一条虚边。

其他操作大致相同。

下面说维护数据。分别维护三组数据和两个标记:实数据,虚数据,全部数据,实标记,虚标记。

对于实链Splay,用实数据维护。虚边Splay,应该是实边Splay上左右儿子的虚数据+虚边Splay左右儿子的全部数据。

全部数据就是实数据加虚数据。

下放标记时,实标记只影响实链Splay的儿子,翻转标记也是,虚标记除了影响所有儿子的虚数据外,还要注意可能影响虚儿子中的实链。

代码奇长无比,可以结合理解。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

const int maxn = 200005;
const int inf = ~0U>>1;

struct tag
{
  int x, y;
  tag() {x = 1; y = 0;}
  tag(int x_, int y_):x(x_),y(y_){}
  bool aval() {
    return x != 1 || y;
  }
  tag operator + (const tag &rhs) const {
    return tag(x*rhs.x, y*rhs.x+rhs.y);
  }
};
int atag(int lhs, tag rhs) {
  return lhs * rhs.x + rhs.y;
}
struct data
{
  int sum, minv, maxv, siz;
  data() {
    sum = siz = 0; minv = inf; maxv = -inf;
  }
  data(int x) {
    sum = minv = maxv = x; siz = 1;
  }
  data(int a, int b, int c, int d) {
    sum = a; minv = b; maxv = c; siz = d;
  }
  data operator + (const data &rhs) {
    return data(sum + rhs.sum, min(minv, rhs.minv), max(maxv, rhs.maxv), siz + rhs.siz);
  }
  friend data operator + (const data &lhs, const tag &rhs) {
    return lhs.siz ? data(lhs.sum * rhs.x + lhs.siz * rhs.y, atag(lhs.minv, rhs), atag(lhs.maxv, rhs), lhs.siz) : lhs;
  }
};
int f[maxn], ch[maxn][4], a[maxn], cnt, rt;
int rub[maxn], rubcnt;
bool rev[maxn], in[maxn];
int val[maxn];

data chains[maxn], subs[maxn], alls[maxn];
tag chaint[maxn], subt[maxn];

inline int isroot(int x, int t) {
  if (t) return !f[x] || !in[f[x]] || !in[x];
  return !f[x] || (ch[f[x]][0] != x && ch[f[x]][1] != x) || in[f[x]] || in[x];
}
inline void rever(int x) {
  if (!x) return;
  swap(ch[x][0], ch[x][1]); rev[x] ^= 1;
}
inline void chain_tag(int x, tag p) {
  if (!x) return;
  chains[x] = chains[x] + p;
  alls[x] = chains[x] + subs[x];
  val[x] = atag(val[x], p);
  chaint[x] = chaint[x] + p;
}
inline void tree_tag(int x, tag p, bool t) {
  if (!x) return;
  subs[x] = subs[x] + p;
  subt[x] = subt[x] + p;
  if (!in[x] && t) chain_tag(x, p);
  else alls[x] = chains[x] + subs[x];
}
inline void pushdown(int x) {
  if (!x) return;
  if (rev[x]) rever(ch[x][0]), rever(ch[x][1]), rev[x] = 0;
  if (!in[x] && chaint[x].aval()) 
    chain_tag(ch[x][0], chaint[x]), 
    chain_tag(ch[x][1], chaint[x]), 
    chaint[x] = tag();
  if (subt[x].aval()) {
    tree_tag(ch[x][0], subt[x], 0);
    tree_tag(ch[x][1], subt[x], 0);
    tree_tag(ch[x][2], subt[x], 1);
    tree_tag(ch[x][3], subt[x], 1);
    subt[x] = tag();
  }
}
inline void pushup(int x) {
  subs[x] = data();
  for (int i = 0; i < 2; ++i) if (ch[x][i]) subs[x] = subs[x] + subs[ch[x][i]];
  for (int i = 2; i < 4; ++i) if (ch[x][i]) subs[x] = subs[x] + alls[ch[x][i]];
  if (in[x]) {
    chains[x] = data();
    alls[x] = subs[x];
  } else {
    chains[x] = data(val[x]);
    for (int i = 0; i < 2; ++i) if(ch[x][i]) chains[x] = chains[x] + chains[ch[x][i]];
    alls[x] = chains[x] + subs[x];
  }
}
inline int get_child(int x, int t) {
  pushdown(ch[x][t]);
  return ch[x][t];
}
inline void rotate(int x, int t) {
  int y = f[x], w = (ch[y][t + 1] == x) + t;
  ch[y][w] = ch[x][w ^ 1];
  if (ch[x][w ^ 1]) f[ch[x][w ^ 1]] = y;
  if (f[y]) 
    for (int z = f[y], i = 0; i < 4; ++i)
      if (ch[z][i] == y)
        ch[z][i] = x;
  f[x] = f[y];
  f[y] = x;
  ch[x][w ^ 1] = y;
  pushup(y);
}
void pushpath (int x, int t) {
  if (!isroot(x, t)) pushpath(x, t);
  pushdown(x);
}
inline void splay(int x, int t = 0) {
  //pushpath(x, t);
  //printf("spl %d %d\n", x, t);
  int y;
  int stk = 1, i = x; a[1] = i;
  while (!isroot(i, t)) a[++stk] = i = f[i];
  while (stk) pushdown(a[stk--]);
  while (!isroot(x, t)) {
    y = f[x];
    if (!isroot(y, t)) {
      rotate(((ch[f[y]][t] == y) ^ (ch[y][t] == x)) ? x : y, t);
    }
    rotate(x, t);
  }
  pushup(x);
}
inline int newnode() {
  int x = (rubcnt ? rub[rubcnt--] : ++cnt);
  ch[x][2] = ch[x][3] = 0; in[x] = 1;
  return x;
}
inline void setson(int x, int t, int y) {
  ch[x][t] = y; f[y] = x;
}
inline int getid(int x) {
  for (int i = 0; i < 4; ++i) if (ch[f[x]][i] == x) return i;
  return 4;
}
inline void ADD(int x, int y) {
  if (!y) return;
  pushdown(x);
  for (int i = 2; i < 4; ++i) if (!ch[x][i]) {
    setson(x, i, y);
    return;
  }
  while (ch[x][2] && in[ch[x][2]]) x = get_child(x, 2);
  int np = newnode();
  setson(np, 2, ch[x][2]);
  setson(np, 3, y);
  setson(x, 2, np);
  splay(np, 2);
}
inline void DEL(int x) {
  if (!x) return;
  splay(x);
  if (!f[x]) return;
  int y = f[x];
  if (in[y]) {
    //pushpath(y, 2);
    int stk = 1, i = y; a[1] = i;
    while (!isroot(i, 2)) a[++stk] = i = f[i];
    while (stk) pushdown(a[stk--]);
    int anc = f[y];
    if (anc) {
      setson(anc, getid(y), get_child(y, getid(x) ^ 1));
      splay(anc, 2);
    }
    rub[++rubcnt] = y;
  } else {
    ch[y][getid(x)] = 0;
    splay(y);
  }
  f[x] = 0;
}
inline int fa(int x) {
  splay(x);
  if (!f[x]) return 0;
  if (!in[f[x]]) return f[x];
  int y = f[x];
  splay(y, 2);
  return f[y];
}
inline int access(int x) {
  int y = 0;
  for (; x; y = x, x = fa(x)) {
    splay(x);
    DEL(y);
    ADD(x, ch[x][1]);
    setson(x, 1, y);
    pushup(x);
  }
  return y;
}
inline int lca(int x, int y) {
  access(x);
  return access(y);
}
inline int findroot(int x) {
  access(x);
  splay(x);
  while (ch[x][0]) x = ch[x][0];
  return x;
}
inline void makeroot(int x) {
  access(x); splay(x); rever(x);
}
inline void link(int x, int y) {
  makeroot(x);
  ADD(y, x);
  access(x);
}
inline void cut(int x) {
  access(x);
  splay(x);
  f[ch[x][0]] = 0;
  ch[x][0] = 0;
  pushup(x);
}
inline void split(int x, int y) {
  makeroot(x);
  access(y);
  splay(y);
}
inline void ChainUpdate(int x, int y, tag p) {
  split(x, y);
  chain_tag(y, p);
}
inline data ChainQuery(int x, int y) {
  split(x, y);
  return chains[y];
}
inline void SubtreeUpdate(int x, tag p) {
  access(x);
  splay(x);
  val[x] = atag(val[x], p);
  for (int i = 2; i < 4; ++i) if (ch[x][i]) tree_tag(ch[x][i], p, 1);
  pushup(x);
  splay(x);
}
inline data SubtreeQuery(int x) {
  access(x); 
  splay(x);
  data ret = data(val[x]);
  for (int i = 2; i < 4; ++i) if (ch[x][i]) ret = ret + alls[ch[x][i]];
  return ret;
}
inline int rd() {
  register int x = 0, f = 0, c = getchar();
  while (!isdigit(c)) {
    if (c == '-') f = 1;
    c = getchar();
  }
  while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
  return f ? -x : x;
}
int n, m, x, y, z, i, Edge[maxn][2];

int main() {
  //freopen("3153.in", "r", stdin);
  //freopen("3153.out","w",stdout);
  n = rd(); m = rd();
  cnt = n;
  for (int i = 1; i < n; ++i) 
    Edge[i][0] = rd(), Edge[i][1] = rd();
  for (int i = 1; i <= n; ++i)
    val[i] = rd(), pushup(i);
  for (int i = 1; i < n; ++i) 
    link(Edge[i][0], Edge[i][1]);
  rt = rd();
  makeroot(rt);
  int Type;
  //puts("begin");
  while (m--) {
    //puts("opt");
    Type = rd();
    switch (Type) {
      case 0: {
        x = rd(); y = rd();
        SubtreeUpdate(x, tag(0, y)); break;
      } case 1: {
        rt = rd();
        makeroot(rt); break;
      } case 2: {
        x = rd(); y = rd(); z = rd();
        ChainUpdate(x, y, tag(0, z)); makeroot(rt); break;
      } case 3: {
        x = rd(); data d = SubtreeQuery(x);
        printf("%d\n", d.minv); break;
      } case 4: {
        x = rd(); data d = SubtreeQuery(x);
        printf("%d\n", d.maxv); break;
      } case 5: {
        x = rd(); y = rd();
        SubtreeUpdate(x, tag(1, y)); break;
      } case 6: {
        x = rd(); y = rd(); z = rd();
        ChainUpdate(x, y, tag(1, z)); makeroot(rt); break;
      } case 7: {
        x = rd(); y = rd(); data d = ChainQuery(x, y);
        printf("%d\n", d.minv); makeroot(rt); break;
      } case 8: {
        x = rd(); y = rd(); data d = ChainQuery(x, y);
        printf("%d\n", d.maxv); makeroot(rt); break;
      } case 9: {
        x = rd(); y = rd();
        if (lca(x, y) == x) continue;
        cut(x); link(y, x); makeroot(rt); break;
      } case 10: {
        x = rd(); y = rd(); data d = ChainQuery(x, y);
        printf("%d\n", d.sum); makeroot(rt); break;
      } case 11: {
        x = rd(); data d = SubtreeQuery(x);
        printf("%d\n", d.sum); break;
      }
    }
  }
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/nishikino-curtis/p/9993762.html