BZOJ 3786

给一棵n个点的点带权的树,有m次操作,操作分三种,询问点到根的路径点权和,子树加,换父亲。

$$n \leq 1\times 10^5,m \leq 3\times 10^5$$

先想LCT,但没办法子树加,所以可以维护进出栈序,这样操作一就是前缀和,操作二就是区间加,操作三就是区间平移,用splay维护即可。

const int MAXN = 100000 + 5;

struct Input {
  char buf[1 << 25], *s;
  
  Input() {
#ifdef LOCAL
    freopen("BZOJ3786.in", "r", stdin);
    freopen("BZOJ3786.out", "w", stdout);
#endif
    fread(s = buf, 1, 1 << 25, stdin);
  }
  
  friend Input &operator>>(Input &io, int &x) {
    x = 0;
    while (!isdigit(*io.s))
      ++ io.s;
    while (isdigit(*io.s))
      x = x * 10 + *io.s ++ - '0';
    return io;
  }
  
  friend Input &operator>>(Input &io, char *s) {
    while (isspace(*io.s))
      ++ io.s;
    while (!isspace(*io.s))
      *s ++ = *io.s ++;
    return io;
  }
} cin;

int arr[MAXN * 2];
bool ok[MAXN * 2];

struct Splay {
  struct Node {
    Node *fa, *ch[2];
    int sz, val, addv;
    bool ok;
    LL sum;
    
    Node() {}
    Node(Node *p, int v, bool o) : fa(p), sz(1), val(v), addv(0), ok(o), sum(v) {
      ch[0] = ch[1] = NULL;
    }
    
    bool relation() {
      return this == fa->ch[1];
    }
    
#define _sz(x) ((x) ? (x)->sz : 0)
#define _sum(x) ((x) ? (x)->sum : 0)
    void push_up() {
      sz = _sz(ch[0]) + (ok ? 1 : -1) + _sz(ch[1]);
      sum = _sum(ch[0]) + val + _sum(ch[1]);
    }
    
    void push_down() {
      if (addv) {
        FOR(i, 0, 2)
          if (ch[i]) {
            ch[i]->addv += addv;
            ch[i]->val += ch[i]->ok ? addv : -addv;
            ch[i]->sum += 1LL * addv * ch[i]->sz;
          }
        addv = 0;
      }
    }
  } *nd[MAXN * 2];
  
  Node *build(Node *par, int l, int r) {
    if (l > r)
      return NULL;
    int mid = (l + r) >> 1;
    nd[mid] = new Node(par, arr[mid], ok[mid]);
    nd[mid]->ch[0] = build(nd[mid], l, mid - 1);
    nd[mid]->ch[1] = build(nd[mid], mid + 1, r);
    nd[mid]->push_up();
    return nd[mid];
  }
  
  void rotate(Node *o) {
    int t = o->relation();
    Node *par = o->fa;
    par->ch[t] = o->ch[t ^ 1];
    if (o->ch[t ^ 1])
      o->ch[t ^ 1]->fa = par;
    if (par->fa)
      par->fa->ch[par->relation()] = o;
    o->fa = par->fa, o->ch[t ^ 1] = par, par->fa = o;
    par->push_up();
    o->push_up();
  }
  
  void splay(Node *o) {
    static Node *stk[MAXN * 2];
    int top = 0;
    for (Node *tmp = o; tmp; tmp = tmp->fa)
      stk[++ top] = tmp;
    Rep(i, top, 1)
      stk[i]->push_down();
    for (; o->fa; rotate(o))
      if (o->fa->fa)
        rotate(o->fa->relation() == o->relation() ? o->fa : o);
  }
  
  Node *split(Node *o, int d) {
    splay(o);
    Node *p = o->ch[d];
    if (p)
      p->fa = NULL;
    o->ch[d] = NULL;
    o->push_up();
    return p;
  }
  
  Node *min(Node *o) {
    Node *k = o;
    for (; k->ch[0]; k = k->ch[0]);
    return k;
  }
  
  Node *max(Node *o) {
    Node *k = o;
    for (; k->ch[1]; k = k->ch[1]);
    return k;
  }
  
  void merge(Node *o, Node *p) {
    if (!o || !p)
      return;
    Node *q = max(o);
    splay(q);
    splay(p);
    q->ch[1] = p;
    p->fa = q;
    q->push_up();
  }
  
  std::pair <Node *, Node *> select(Node *l, Node *r) {
    std::pair <Node *, Node *> res;
    res.F = split(l, 0), res.S = split(r, 1);
    return res;
  }
  
  LL query(Node *l, Node *r) {
    std::pair <Node *, Node *> tmp = select(l, r);
    splay(l);
    LL ans = l->sum;
    merge(tmp.F, l);
    merge(l, tmp.S);
    return ans;
  }
  
  void modify(Node *l, Node *r, int x) {
    std::pair <Node *, Node *> tmp = select(l, r);
    splay(l);
    l->addv += x;
    l->val += l->ok ? x : -x;
    l->sum += 1LL * l->sz * x;
    merge(tmp.F, l);
    merge(l, tmp.S);
  }
  
  void change(Node *l, Node *r, Node *target) {
    std::pair <Node *, Node *> tmp = select(l, r);
    merge(tmp.F, tmp.S);
    Node *c = split(target, 1);
    merge(target, l);
    merge(l, c);
  }
} S;

struct Tree {
  int hed[MAXN], nxt[MAXN * 2], to[MAXN * 2], val[MAXN], fa[MAXN], L[MAXN], R[MAXN], cnt, dfn;
  
  void add_edge(int u, int v) {
    ++ cnt;
    to[cnt] = v;
    nxt[cnt] = hed[u];
    hed[u] = cnt;
  }
  
  void DFS(int u) {
    ++ dfn;
    arr[dfn] = val[u];
    ok[dfn] = 1;
    L[u] = dfn;
    for (int e = hed[u]; e; e = nxt[e]) {
      int v = to[e];
      if (v != fa[u]) {
        fa[v] = u;
        DFS(v);
      }
    }
    ++ dfn;
    arr[dfn] = -val[u];
    ok[dfn] = 0;
    R[u] = dfn;
  }
} T;

int main() {
  int n;
  cin >> n;
  For(i, 2, n) {
    int par;
    cin >> par;
    T.add_edge(par, i);
    T.add_edge(i, par);
  }
  For(i, 1, n)
    cin >> T.val[i];
  T.DFS(1);
  S.build(NULL, 1, n * 2);
  int m;
  cin >> m;
  For(i, 1, m) {
    static char opt[5];
    cin >> opt;
    if (opt[0] == 'Q') {
      int d;
      cin >> d;
      printf("%lld\n", S.query(S.nd[1], S.nd[T.L[d]]));
    } else if (opt[0] == 'C') {
      int x, y;
      cin >> x >> y;
      S.change(S.nd[T.L[x]], S.nd[T.R[x]], S.nd[T.L[y]]);
    } else {
      int p, q;
      cin >> p >> q;
      S.modify(S.nd[T.L[p]], S.nd[T.R[p]], q);
    }
  }
  return 0;
}

 

posted @ 2018-10-13 00:08  sjkmost  阅读(213)  评论(0编辑  收藏  举报