JZOJ5662. 【GDOI2018Day1模拟4.17】尺树寸泓

这里写图片描述
这里写图片描述

题目大意

给出一棵二叉树,
有左旋和右旋操作,
询问某个点子树的size的乘积。

题解

平衡树有一个很重要的性质:
无论怎样旋转,这棵树的中序遍历是一定不会变的。
而一个节点的子树在中序遍历里面是连续的一段,
也就是要求中序遍历中间某一段连续的size的乘积。

而每次旋转操作,无论左旋还是右旋,都只会改变两个点,
每次旋转的时候就修改两个点的size,左右儿子,以及它子树在中序遍历中对于的区间,
用线段树维护size的乘积,单点修改,查询区间。

code

#include <queue>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <time.h>
#define ll long long
#define N 200003
#define M 103
#define db double
#define P putchar
#define G getchar
#define mo 1000000007
#define pi 3.1415926535897932384626433832795
using namespace std;
char ch;
void read(int &n)
{
    n=0;
    ch=G();
    while((ch<'0' || ch>'9') && ch!='-')ch=G();
    ll w=1;
    if(ch=='-')w=-1,ch=G();
    while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
    n*=w;
}

int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
ll sqr(ll x){return x*x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}

ll g[N*4],s[N];
int f[N],son[2][N],v[N],dfn[N],l[N],r[N];
int n,q,opt,x,id,opl,opr,ops,pos[N];

void build(int x,int l,int r) 
{
    if(l==r)
    {
        g[x]=s[dfn[l]];
        return;
    }
    int m=(l+r)>>1;
    build(x<<1,l,m);
    build((x<<1)|1,m+1,r);
    g[x]=g[x<<1]*g[(x<<1)|1]%mo;
}

void find(int x,int l,int r)
{
    if(opl<=l && r<=opr)
    {
        ops=ops*g[x]%mo;
        return;
    }
    int m=(l+r)>>1;
    if(opl<=m)find(x<<1,l,m);
    if(m<opr)find((x<<1)|1,m+1,r);
}

void work(int x,int l,int r)
{
    if(l==r)
    {
        g[x]=s[dfn[l]];
        return;
    }
    int m=(l+r)>>1;
    if(opl<=m)work(x<<1,l,m);
        else work((x<<1)|1,m+1,r);
    g[x]=g[x<<1]*g[(x<<1)|1]%mo;    
}

void rotate(int x,int w)//1:l 0:r
{   
    int y=son[w][x];
    if(!y)return;
    s[x]=(s[x]-s[y]+s[son[1-w][y]]+mo)%mo;
    s[y]=(s[x]+s[son[w][y]]+v[y]+mo)%mo;

    f[son[1-w][y]]=x;
    son[w][x]=son[1-w][y];
    f[y]=f[x];son[son[1][f[x]]==x?1:0][f[x]]=y;
    f[x]=y;son[1-w][y]=x;

    l[x]=son[0][x]?l[son[0][x]]:pos[x];r[x]=son[1][x]?r[son[1][x]]:pos[x];
    l[y]=son[0][y]?l[son[0][y]]:pos[y];r[y]=son[1][y]?r[son[1][y]]:pos[y];

    opl=pos[x];work(1,1,n);
    opl=pos[y];work(1,1,n);
}

void dfs(int x)
{
    if(!x)return;
    l[x]=id+1;
    dfs(son[0][x]);
    dfn[++id]=x;pos[x]=id;
    dfs(son[1][x]);
    r[x]=id;
}

int main()
{
    read(n);read(q);
    for(int i=1;i<=n;i++)
        read(v[i]),read(son[0][i]),read(son[1][i]),
            f[son[0][i]]=i,f[son[1][i]]=i;
    s[0]=f[0]=0;

    for(int i=n;i;i--)
        s[i]=(s[son[0][i]]+s[son[1][i]]+v[i])%mo;

    dfs(1);build(1,1,n);

    for(;q;q--)
    {
        read(opt);read(x);
        if(opt==2)
        {
            ops=1;opl=l[x];opr=r[x];
            find(1,1,n);
            write(ops);P('\n');
        }else rotate(x,opt);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/lijf2001/article/details/80048141