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;
}