题意:维护一个线段树,有两种更新,一种是修改一个区间的值。一种是在一个区间内把所有大于x的数改成这个数与x的最大公约数。
代码如下
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cstdio>
#include<map>
#include<cmath>
#include<assert.h>
#include<iomanip>
#include<assert.h>
using namespace std;
typedef long long ll;
const int maxn = 400005;
int gcd(int a,int b)
{
int c = a%b;
for(;c!=0;c=a%b){
a = b;
b = c;
}
return b;
}
int valv[maxn];
int maxv[maxn];
void pushdown(int l,int r,int o)
{
if(l == r)return;
if(valv[o]==-1)return;
valv[o*2] = valv[o];
valv[o*2+1] = valv[o];
maxv[o*2] = valv[o*2];
maxv[o*2+1] = valv[o*2+1];
valv[o] = -1;
}
int yl,yr;
int v;
void update1(int l,int r,int o)
{
if(yl<=l&&yr>=r){
valv[o] = v;
maxv[o] = valv[o];
return;
}
int m = (l+r);m>>=1;
pushdown(l,r,o);
if(yl<=m){
update1(l,m,o*2);
}
if(yr>m){
update1(m+1,r,o*2+1);
}
maxv[o] = max(maxv[o*2],maxv[o*2+1]);
}
void update2(int l,int r,int o)
{
if(maxv[o]<v)return;
if(yl<=l&&yr>=r&&valv[o]>=0){
valv[o] = gcd(valv[o],v);
maxv[o] = valv[o];
return;
}
pushdown(l,r,o);
int m = l+r;m>>=1;
if(yl<=m){
update2(l,m,o*2);
}
if(yr>m){
update2(m+1,r,o*2+1);
}
maxv[o] = max(maxv[o*2],maxv[o*2+1]);
}
void solve(int l,int r,int o)
{
int m = l+r;m>>=1;
if(valv[o] >=0){
for(int i=l;i<=r;++i){
printf("%d ",valv[o]);
}
return;
}
solve(l,m,o*2);
solve(m+1,r,o*2+1);
}
int main()
{
// freopen("data.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--){
memset(maxv,-1,sizeof(maxv));
memset(valv,-1,sizeof(valv));
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i){
int a;
scanf("%d",&a);
yl = i;yr = i;
v = a;
update1(1,n,1);
}
int q;
scanf("%d",&q);
while(q--){
int t;
scanf("%d%d%d%d",&t,&yl,&yr,&v);
if(t == 1)
update1(1,n,1);
else {
update2(1,n,1);
}
}
solve(1,n,1);
puts("");
}
return 0;
}