看了题目觉得是线段树的题目,想了一下觉得不用线段树也能做。
从后往回读,读到是1的话,记录该点的值,修改dp[l]-dp[r],修改为r-i+1代表读到这点可以跳过的点的个数。
读到2的话,记录在gc数组,最后做公约数操作。
如果sum==n即每个数都被1过了,说明之前的操作已经不用看了,直接break;
算是水过了数据。
#include<stdio.h>
#include<string.h>
const int M=100005;
int a[M],t[M],l[M],r[M],x[M],dp[M],gc[M][100],num[M];
int gcd(int a,int b)
{
int t;
while(b!=0)
{
t=a;
a=b;
b=t%b;
}
return a;
}
int main()
{
int T,n,i,q,j,k,sum;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
scanf("%d",&q);
for(i=1;i<=q;i++)
scanf("%d%d%d%d",&t[i],&l[i],&r[i],&x[i]);
for(i=1;i<=n;i++)
{
dp[i]=0;
gc[i][0]=0;
num[i]=0;
}
sum=0;
for(i=q;i>=1;i--)
{
if(t[i]==1)
{
for(j=l[i];j<=r[i];)
{
if(dp[j]==0)
{
dp[j]=r[i]-j+1;
sum++;
a[j]=x[i];
j++;
}
else
{
j+=dp[j];
}
}
}
if(t[i]==2)
{
if(x[i]==0) continue;
for(j=l[i];j<=r[i];)
{
if(dp[j]==0)
{
if(gc[j][num[j]]>=x[i])
{
for(k=1;k<=num[j];k++)
{
if(gc[j][num[j]-k]<x[i]) break;
}
num[j]=num[j]-k+1;
gc[j][num[j]]=x[i];
}
else
{
num[j]++;
gc[j][num[j]]=x[i];
}
j++;
}
else
{
j+=dp[j];
}
}
if(sum==n) break;
}
}
for(i=1;i<=n;i++)
{
for(j=num[i];j>=0;j--)
{
if(a[i]>gc[i][j])
a[i]=gcd(a[i],gc[i][j]);
}
}
for(i=1;i<=n;i++)
printf("%d ",a[i]);
printf("\n");
}
return 0;
}