看了题目觉得是线段树的题目,想了一下觉得不用线段树也能做。
从后往回读,读到是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; }