2019南昌网络赛 Yukino With Subinterval —— 树套树(树状数组套主席树)

This way

题意:

给你一个长度为n的数组,定义区间L~R的最长相同子串为
在这里插入图片描述
在上面这个条件下长度要求最长。
每次有两种操作:
1 x y表示将x位置上的数变成y
2 x y l r表示询问x到y区间,值在l到r之间的最长相同子串的数量有多少

题解:

想要了解树套树的可以去看一下我博客哦
那么先考虑第二个询问,我们只在连续的相同的a的第一个位置放1,然后查询的话依旧查x-1~y,然后再查看a[x]是否等于a[y-1]并且在l到r范围内。由于这次是区间查询,所以就不能像上次一样直接变换root和last,需要新开数组。
其它没什么新鲜的东西了,这次必须要优化开点才能过去,要不然会在RE和MLE之间来回跳跃。
最后还有一个要注意的点就是操作1的时候的5个判断,要考虑这个点和上一个,下一个点的值是否相同的所有情况。
时间复杂度还行,空间的话我是按最大的开的.

在这里插入图片描述

#include
using namespace std;
const int N=2e5+5;
struct Chairman{
    int ls[N*220],rs[N*220],rt[N],num[N*220],tot;
    void update(int l,int r,int &root,int p,int v){
        if(!root)root=++tot;
        num[root]+=v;
        if(l==r)return ;
        int mid=l+r>>1;
        if(mid>=p)
            update(l,mid,ls[root],p,v);
        else
            update(mid+1,r,rs[root],p,v);
    }
    int query(int l,int r,int *root,int *last,int ql,int qr){
        int sum=0,mid=l+r>>1;
        if(l>=ql&&r<=qr){
            for(int i=1;i<=root[0];i++)sum+=num[root[i]];
            for(int i=1;i<=last[0];i++)sum-=num[last[i]];
            return sum;
        }
        int ans=0,nr[25],nl[25];
        nr[0]=root[0],nl[0]=last[0];
        if(mid>=ql){
            for(int i=1;i<=root[0];i++)nr[i]=ls[root[i]];
            for(int i=1;i<=last[0];i++)nl[i]=ls[last[i]];
            ans=query(l,mid,nr,nl,ql,qr);
        }
        if(mid<qr){
            for(int i=1;i<=root[0];i++)nr[i]=rs[root[i]];
            for(int i=1;i<=last[0];i++)nl[i]=rs[last[i]];
            ans+=query(mid+1,r,nr,nl,ql,qr);
        }
        return ans;
    }
}cmt;
int all,n,m;
int lowbit(int x){return x&(-x);}
void update(int l,int r,int root,int p,int v){
    for(int i=root;i<=n;i+=lowbit(i)){
        cmt.update(l,r,cmt.rt[i],p,v);
    }
}
int root[50],last[50];
struct Operator{
    int op,x,y,l,r;
}op[N];
int a[N];
int query(int id){
    int x=op[id].x,y=op[id].y,l=op[id].l,r=op[id].r;
    root[0]=last[0]=0;
    for(int i=y;i;i-=lowbit(i))
        root[0]++,root[root[0]]=cmt.rt[i];
    for(int i=x-1;i;i-=lowbit(i))
        last[0]++,last[last[0]]=cmt.rt[i];
    return cmt.query(1,n,root,last,l,r);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        if(a[i]!=a[i-1])
            update(1,n,i,a[i],1);
    }
    for(int i=1;i<=m;i++){
        scanf("%d",&op[i].op);
        if(op[i].op==1){
            scanf("%d%d",&op[i].x,&op[i].y);
            int x=op[i].x;
            if(a[x]==op[i].y)continue;
            if(a[x]!=a[x-1])update(1,n,x,a[x],-1);
            if(a[x]==a[x+1])update(1,n,x+1,a[x],1);
            a[x]=op[i].y;
            if(a[x]!=a[x-1])update(1,n,x,a[x],1);
            if(a[x]==a[x+1]&&a[x]!=a[x-1])update(1,n,x+1,a[x],-1);
            if(a[x]==a[x-1]&&a[x]==a[x+1])update(1,n,x+1,a[x],-1);
        }
        else{
            scanf("%d%d%d%d",&op[i].x,&op[i].y,&op[i].l,&op[i].r);
            printf("%d\n",query(i)+(a[op[i].x]==a[op[i].x-1]&&a[op[i].x]>=op[i].l&&a[op[i].x]<=op[i].r));
        }
    }
    return 0;
}

你可能感兴趣的:(主席树,树套树,树状数组)