JZOJ 5662. 【GDOI2018Day1模拟4.17】尺树寸泓

Description

Description

Input

Input

Output

Output

Sample Input

3 4
1 2 3
1 0 0
1 0 0
2 1
0 1
2 2
2 1

Sample Output

3
6
2

Data Constraint

Data Constraint

Solution

  • 一开始看错题了,以为直接修改就可以了,结果爆零……

  • 这题显然LCT可以做,要多暴力有多暴力。

  • 但我们用些巧法,发掘一下性质。

  • 这左旋右旋就相当于Splay的操作,而操作前后中序遍历不变!

  • 而一个点子树对应的区间在中序遍历中是连续的一段。

  • 于是我们就可以根据中序遍历开一颗线段树,维护区间乘积。

  • 而旋转操作实际上只会改变两个点的子树区间,分类讨论并单点修改即可。

  • 时间复杂度 O(N log N)

Code

#include<cstdio>
#include<cctype>
using namespace std;
const int N=2e5+5,mo=1e9+7;
int tot,qx,qy,top;
long long qz;
int id[N],fa[N],size[N],s[N][2],pre[N],key[N],begin[N],st[N];
long long a[N],sum[N],mul[N<<2];
inline int read()
{
    int X=0,w=0; char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) X=(X<<1)+(X<<3)+(ch^48),ch=getchar();
    return w?-X:X;
}
inline void update(int x)
{
    size[x]=size[s[x][0]]+size[s[x][1]]+1;
    sum[x]=(a[begin[x]+size[x]-1]-a[begin[x]-1]+mo)%mo;
}
void dfs(int x)
{
    begin[x]=tot+1;
    if(s[x][0]) dfs(s[x][0]);
    id[x]=++tot;
    pre[id[x]]=x;

    if(s[x][1]) dfs(s[x][1]);
    size[x]=size[s[x][0]]+size[s[x][1]]+1;
}
void bfs(int rt)
{
    while(top || rt)
    {
        while(rt)
        {
            begin[rt]=tot+1;
            st[++top]=rt;
            rt=s[rt][0];
        }
        rt=st[top--];
        id[rt]=++tot;
        pre[id[rt]]=rt;
        rt=s[rt][1];
    }
    int l=0,r=1;
    st[1]=1;
    while(l<r)
    {
        int x=st[++l];
        if(s[x][0]) st[++r]=s[x][0];
        if(s[x][1]) st[++r]=s[x][1];
    }
    for(int i=r;i;i--) size[i]=size[s[i][0]]+size[s[i][1]]+1;
}
void make(int v,int l,int r)
{
    if(l==r)
    {
        mul[v]=sum[pre[l]]%mo;
        return;
    }
    int mid=l+r>>1;
    make(v<<1,l,mid);
    make(v<<1|1,mid+1,r);
    mul[v]=mul[v<<1]*mul[v<<1|1]%mo;
}
void change(int v,int l,int r)
{
    if(l==r)
    {
        mul[v]=qz;
        return;
    }
    int mid=l+r>>1;
    if(qx<=mid) change(v<<1,l,mid); else change(v<<1|1,mid+1,r);
    mul[v]=mul[v<<1]*mul[v<<1|1]%mo;
}
long long find(int v,int l,int r)
{
    if(qx<=l && r<=qy) return mul[v];
    int mid=l+r>>1;
    long long ss=1;
    if(qx<=mid) ss=find(v<<1,l,mid);
    if(qy>mid) ss=ss*find(v<<1|1,mid+1,r)%mo;
    return ss;
}
inline bool pd(int x)
{
    return s[fa[x]][1]==x;
}
int main()
{
    freopen("splay.in","r",stdin);
    freopen("splay.out","w",stdout);
    int n=read(),q=read();
    for(int i=1;i<=n;i++)
    {
        key[i]=read();
        int x=read(),y=read();
        if(x) fa[s[i][0]=x]=i;
        if(y) fa[s[i][1]=y]=i;
    }
    dfs(1);
    for(int i=1;i<=n;i++) a[i]=(a[i-1]+key[pre[i]])%mo;
    for(int i=1;i<=n;i++) sum[i]=(a[begin[i]+size[i]-1]-a[begin[i]-1]+mo)%mo;
    make(1,1,n);
    while(q--)
    {
        int opt=read(),x=read();
        if(opt==2)
        {
            qx=begin[x],qy=begin[x]+size[x]-1;
            printf("%lld\n",(find(1,1,n)+mo)%mo);
        }else
        if(opt==1)
        {
            int y=s[x][1];
            if(!y) continue;
            if(fa[y]=fa[x]) s[fa[x]][pd(x)]=y;
            fa[y]=fa[x];
            if(s[x][1]=s[y][0]) fa[s[y][0]]=x;
            fa[s[y][0]=x]=y;
            begin[y]=begin[x];
            update(x);
            update(y);
            qx=id[x],qz=sum[x];
            change(1,1,n);
            qx=id[y],qz=sum[y];
            change(1,1,n);
        }else
        {
            int y=s[x][0];
            if(!y) continue;
            if(fa[y]=fa[x]) s[fa[x]][pd(x)]=y;
            if(s[x][0]=s[y][1]) fa[s[y][1]]=x;
            fa[s[y][1]=x]=y;
            begin[x]=id[y]+1;
            update(x);
            update(y);
            qx=id[x],qz=sum[x];
            change(1,1,n);
            qx=id[y],qz=sum[y];
            change(1,1,n);
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值