[线段树模拟平衡树] HDU4942. Game on S♂play

刚开始想用Splay、Treap什么的维护dfs序…打起来贼烦
打完后vectorxj大佬说用中序遍历就好了…

因为旋转后一棵树的中序遍历是不会变的,那么每次旋转就是改变了下子树在中序遍历中的区间,然后用线段树模拟一下就好了。

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

using namespace std;

const int N=100010,P=1e9+7;

int t,n,m,cnt;
int l[N],r[N],L[N],R[N],v[N],w[N],p[N],Q[N],fa[N];
int pro[N<<2];

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline void rea(int &x){
  char c=nc(); x=0;
  for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}

void Up(int x){
  v[x]=(1LL*w[x]+v[l[x]]+v[r[x]])%P;
}

void dfs(int x){
  L[x]=cnt+1;
  if(l[x]) dfs(l[x]);
  p[x]=++cnt; Q[cnt]=x;
  if(r[x]) dfs(r[x]);
  R[x]=cnt;
  Up(x);
}

void Build(int g,int l,int r){
  if(l==r) return pro[g]=v[Q[l]],void();
  int mid=l+r>>1;
  Build(g<<1,l,mid); Build(g<<1|1,mid+1,r);
  pro[g]=1LL*pro[g<<1]*pro[g<<1|1]%P;
}

void Modify(int g,int l,int r,int x,int y){
  if(l==r) return pro[g]=y,void();
  int mid=l+r>>1;
  if(x<=mid) Modify(g<<1,l,mid,x,y);
  else Modify(g<<1|1,mid+1,r,x,y);
  pro[g]=1LL*pro[g<<1]*pro[g<<1|1]%P;
}

int Query(int g,int L,int R,int l,int r){
  if(L==l && r==R) return pro[g];
  int mid=L+R>>1;
  if(r<=mid) return Query(g<<1,L,mid,l,r);
  else if(l>mid) return Query(g<<1|1,mid+1,R,l,r);
  else return 1LL*Query(g<<1,L,mid,l,mid)*Query(g<<1|1,mid+1,R,mid+1,r)%P;
}

int main(){
  rea(t); int CASE=0;
  while(t--){
    rea(n); rea(m); cnt=0;
    fa[1]=0;
    for(int i=1;i<=n;i++)
      rea(w[i]),rea(l[i]),rea(r[i]),fa[l[i]]=fa[r[i]]=i;
    dfs(1);
    Build(1,1,n);
    printf("Case #%d:\n",++CASE);
    while(m--){
      int opt,x;
      rea(opt); rea(x);
      if(opt==0){
    int y=l[x];
    if(!y) continue;

    if(fa[x]){
      if(l[fa[x]]==x) l[fa[x]]=y; else r[fa[x]]=y;
    }
    fa[y]=fa[x];
    if(l[x]=r[y]) fa[l[x]]=x;
    fa[r[y]=x]=y;
    Up(x); Up(y);

    L[x]=p[y]+1; R[y]=R[x];
    Modify(1,1,n,p[x],v[x]); Modify(1,1,n,p[y],v[y]);
      }

      else if(opt==1){
    int y=r[x];
    if(!y) continue;
    if(fa[x]){
      if(l[fa[x]]==x) l[fa[x]]=y; else r[fa[x]]=y;
    }
    fa[y]=fa[x];
    if(r[x]=l[y]) fa[r[x]]=x; l[y]=x;
    fa[x]=y;
    Up(x); Up(y);
    R[x]=p[y]-1; L[y]=L[x];
    Modify(1,1,n,p[x],v[x]); Modify(1,1,n,p[y],v[y]);
      }
      else{
    printf("%d\n",Query(1,1,n,L[x],R[x]));
      }
    }
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值