zoukankan      html  css  js  c++  java
  • BZOJ3786 : 星系探索

    由于没有换根操作,所以直接用Splay维护DFS括号序列即可。

    对于查询1到x路径和,就是已入栈的减去已出栈的。

    子树加相当于区间加。

    换父亲相当于一个区间的移动。

    本题非常卡常数,一开始直接扒3153的代码狂T不止,改写Splay后也是狂T不止,最后把Splay从数组储存改成结构体储存才AC。

    #include<cstdio>
    #define N 200010
    typedef long long ll;
    struct P{
      int f,son[2],ci,co;ll val,tag,sum;bool is;
      P(){f=son[0]=son[1]=ci=co=val=tag=sum=is=0;}
    }T[N];
    int n,m,i,x,y,root,a[N],g[N],nxt[N],v[N],ed,st[N],en[N],dfn,w[N];
    char ch;
    inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
    inline void addedge(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
    void dfs(int x){
      T[st[x]=++dfn].val=w[x],T[dfn].is=1;
      for(int i=g[x];i;i=nxt[i])dfs(v[i]);
      T[en[x]=++dfn].val=w[x];
    }
    inline void add1(int x,ll p){
      if(!x)return;
      T[x].val+=p;T[x].sum+=p*(T[x].ci-T[x].co);T[x].tag+=p;
    }
    inline void pb(int x){if(T[x].tag)add1(T[x].son[0],T[x].tag),add1(T[x].son[1],T[x].tag),T[x].tag=0;}
    inline void up(int x){
      if(T[x].is)T[x].ci=1,T[x].co=0,T[x].sum=T[x].val;else T[x].ci=0,T[x].co=1,T[x].sum=-T[x].val;
      T[x].ci+=T[T[x].son[0]].ci+T[T[x].son[1]].ci;
      T[x].co+=T[T[x].son[0]].co+T[T[x].son[1]].co;
      T[x].sum+=T[T[x].son[0]].sum+T[T[x].son[1]].sum;
    }
    inline void rotate(int x){
      int y=T[x].f,w=T[y].son[1]==x;
      T[y].son[w]=T[x].son[w^1];
      if(T[x].son[w^1])T[T[x].son[w^1]].f=y;
      if(T[y].f){
        int z=T[y].f;
        if(T[z].son[0]==y)T[z].son[0]=x;
        if(T[z].son[1]==y)T[z].son[1]=x;
      }
      T[x].f=T[y].f;T[x].son[w^1]=y;T[y].f=x;up(y);
    }
    inline void splay(int x,int w){
      int s=1,i=x,y;a[1]=x;
      while(T[i].f)a[++s]=i=T[i].f;
      while(s)pb(a[s--]);
      while(T[x].f!=w){
        y=T[x].f;
        if(T[y].f!=w){if((T[T[y].f].son[0]==y)^(T[y].son[0]==x))rotate(x);else rotate(y);}
        rotate(x);
      }
      if(!w)root=x;
      up(x);
    }
    int build(int l,int r,int fa){
      int x=(l+r)>>1;
      T[x].f=fa;
      if(l==r){return up(x),x;}
      if(l<x)T[x].son[0]=build(l,x-1,x);
      if(r>x)T[x].son[1]=build(x+1,r,x);
      return up(x),x;
    }
    inline int get(int x,int y){
      while(T[x].son[y])x=T[x].son[y];
      return x;
    }
    inline void add(int x,int p){
      splay(st[x],0);
      splay(en[x],root);
      add1(T[en[x]].son[0],p);
      T[en[x]].val+=p,up(en[x]);
      T[st[x]].val+=p,up(st[x]);
    }
    inline void move(int x,int y){
      splay(st[x],0);
      int l=get(T[root].son[0],1);
      splay(en[x],0);
      int r=get(T[root].son[1],0);
      splay(l,0);
      splay(r,root);
      int t=T[r].son[0];
      T[r].son[0]=0,up(r),up(l);
      splay(st[y],0);
      r=get(T[root].son[1],0);
      splay(st[y],0);
      splay(r,root);
      T[r].son[0]=t;
      T[t].f=r;
      up(r),up(root);
    }
    inline ll ask(int x){
      splay(st[x],0);
      return T[T[root].son[0]].sum+T[root].val;
    }
    int main(){
      read(n);
      for(i=2;i<=n;i++)read(x),addedge(x,i);
      for(i=1;i<=n;i++)read(w[i]);
      dfs(1);
      root=build(1,dfn,0);
      read(m);
      while(m--){
        while(!(((ch=getchar())=='Q')||(ch=='C')||(ch=='F')));read(x);
        if(ch=='F')read(y),add(x,y);
        if(ch=='C')read(y),move(x,y);
        if(ch=='Q')printf("%lld
    ",ask(x));
      }
      return 0;
    }
    

      

  • 相关阅读:
    创建逻辑卷LVM以及swap分区
    Linux下命令别名配置
    vim多行注释与删除
    Linux下parted分区超过2TB硬盘-分区格式化
    scp命令限速远程拷贝
    tar命令加密压缩/解密解压
    centos下dnsmasq安装与配置
    Mac OS: xcrun: error: invalid active developer path, missing xcrun
    C/C++编译器GCC:GNU Compiler Collection
    es分页查询限制的问题
  • 原文地址:https://www.cnblogs.com/clrs97/p/4403195.html
Copyright © 2011-2022 走看看