[线段树]HDU 4942——Game on S♂play

题目梗概

给出一棵树,定义一个节点的有趣值为该节点为根的树的权值和。

现在可以旋转一个节点,询问任意子树的有趣值之积。

解题思路

不管树怎么旋转,这棵树的中序遍历是不变的。

维护每个节点控制范围和有趣值。

用线段树维护有趣值的积。

#pragma comment (linker,"/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#define LL long long
#define maxn 100005
#define tt 1000000007
#define ls x<<1
#define rs (x<<1)+1
using namespace std;
struct jz{
    int son[2],L,R,fa;
    LL w;
}a[maxn],t[maxn*4];
int T,n,m,w[maxn],tot,id[maxn],h[maxn];
inline int _read(){
    int num=0;char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();
    return num;
}
inline int min(int x,int y){if (x<y) return x;return y;}
inline int max(int x,int y){if (x>y) return x;return y;}
void updata(int x){t[x].w=(t[ls].w*t[rs].w)%tt;}
void renew(int x){
    a[x].L=a[x].R=id[x];a[x].w=w[x];
    for (int i=0;i<2;i++) if (a[x].son[i]){
        a[x].L=min(a[x].L,a[a[x].son[i]].L);a[x].R=max(a[x].R,a[a[x].son[i]].R);
        a[x].w+=a[a[x].son[i]].w;
    }
}
void DFS(int x){
    if (!x) return;
    DFS(a[x].son[0]);
    id[x]=++tot;h[tot]=x;
    DFS(a[x].son[1]);
    renew(x);
}
void Build(int x,int L,int R){
    t[x].L=L,t[x].R=R;
    if (L==R){t[x].w=a[h[L]].w;return;}
    int mid=L+(R-L>>1);
    Build(ls,L,mid);Build(rs,mid+1,R);
    updata(x);
}
void change(int x,int p,LL y){
    if (t[x].L==t[x].R){t[x].w=y;return;}
    int mid=t[x].L+(t[x].R-t[x].L>>1);
    if (p<=mid) change(ls,p,y);else change(rs,p,y);
    updata(x);
}
LL query(int x,int L,int R){
    if (L==t[x].L&&R==t[x].R) return t[x].w;
    int mid=t[x].L+(t[x].R-t[x].L>>1);
    if (R<=mid) return query(ls,L,R);else
    if (L>mid) return query(rs,L,R);else
    return (query(ls,L,mid)*query(rs,mid+1,R))%tt;
}
void turn(int x,int d){
    int t=a[x].son[d],ff=a[x].fa;
    a[x].son[d]=a[t].son[d^1];a[a[t].son[d^1]].fa=x;a[t].son[d^1]=x;
    if (ff) a[ff].son[x!=a[ff].son[0]]=t;
    a[t].fa=ff;a[x].fa=t;
    renew(x);renew(t);
    change(1,id[x],a[x].w);change(1,id[t],a[t].w);
}
int main(){
    freopen("exam.in","r",stdin);
    freopen("exam.out","w",stdout);
    T=_read();
    for (int t=1;t<=T;t++){
        n=_read(),m=_read();
        memset(a,0,sizeof(a));
        for (int i=1;i<=n;i++){
            w[i]=_read(),a[i].son[0]=_read(),a[i].son[1]=_read();
            if (a[i].son[0]) a[a[i].son[0]].fa=i;
            if (a[i].son[1]) a[a[i].son[1]].fa=i;
        }
        tot=0;DFS(1);Build(1,1,n);
        printf("Case #%d:\n",t);
        for (int i=1;i<=m;i++){
            int y=_read(),x=_read();
            if (y==2) printf("%lld\n",query(1,a[x].L,a[x].R)%tt);
            if (y==0&&a[x].son[0]) turn(x,0);
            if (y==1&&a[x].son[1]) turn(x,1);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值