hdu 4092 Nice boat (第四场多校)

看了题目觉得是线段树的题目,想了一下觉得不用线段树也能做。

从后往回读,读到是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;
}


你可能感兴趣的:(多校联赛)