zoukankan      html  css  js  c++  java
  • BZOJ 3786

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

    $$n leq 1 imes 10^5,m leq 3 imes 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
    ", 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;
    }
  • 相关阅读:
    如何在word中添加视频
    在vc中使用MapX时,如何在视图类中响应鼠标消息
    在vc6中检查一个目录是否存在,如果不存在就创建该目录
    Google推出中文图书搜索简体中文试用版(zz)
    用敏捷软件方法开发界面(zz)
    选择文件对话框的封装
    在vc6中如何使某个状态栏的按钮使能和失效
    MapX对图层的引用和创建实例
    有尊严的生命(zz)
    三十岁的男人(zz)
  • 原文地址:https://www.cnblogs.com/sjkmost/p/9781381.html
Copyright © 2011-2022 走看看