给定数列,有2种操作,分别是区间内所有数置成一个数x,区间内所有大于x的数和x求gcd。输出所有操作完成后的数列。
操作和数列长度均为10^5。
建立线段树,记录区间内是否所有元素的值都一样。如果一样就直接求gcd,否则查看子区间。
复杂度感觉上应该是m*logn*logn的。因为一个数最多求log次gcd就会变成1,然后大家就都一样了。区间修改的话最多分成log个区间。具体不会算...
#include <cstdio>
inline int gcd(int x,int y) {
if (x==0) return y;
if (y==0) return x;
int z=x%y;
while (z) {
x=y;y=z;z=x%y;
}
return y;
}
int n,x;
int a[100001];
struct SeqNode {
SeqNode *ls,*rs;
int v;
void down() {
if (v!=-1) ls->v=rs->v=v;
}
void repair() {
if (ls->v==rs->v) v=ls->v;
else v=-1;
}
};
SeqNode b[200000],*bp,*root;
SeqNode *maketree(int l,int r) {
SeqNode *ans=bp++;
if (l==r) {
ans->ls=ans->rs=NULL;
ans->v=a[l];
} else {
int t=(l+r)/2;
ans->ls=maketree(l,t);
ans->rs=maketree(t+1,r);
ans->repair();
}
return ans;
}
void set1(SeqNode *from,int l,int r,int ll,int rr) {
if (l==ll&&r==rr) {
from->v=x;
} else {
int t=(l+r)/2;
from->down();
if (rr<=t) set1(from->ls,l,t,ll,rr);
else if (ll>t) set1(from->rs,t+1,r,ll,rr);
else {
set1(from->ls,l,t,ll,t);
set1(from->rs,t+1,r,t+1,rr);
}
from->repair();
}
}
void set2(SeqNode *from,int l,int r,int ll,int rr) {
if (l==ll&&r==rr&&from->v!=-1) {
if (from->v>x) from->v=gcd(from->v,x);
} else {
int t=(l+r)/2;
from->down();
if (rr<=t) set2(from->ls,l,t,ll,rr);
else if (ll>t) set2(from->rs,t+1,r,ll,rr);
else {
set2(from->ls,l,t,ll,t);
set2(from->rs,t+1,r,t+1,rr);
}
from->repair();
}
}
void godown(SeqNode *from,int l,int r) {
if (l==r) a[l]=from->v;
else {
int t=(l+r)/2;
from->down();
godown(from->ls,l,t);
godown(from->rs,t+1,r);
}
}
int main() {
int t,q,i;
scanf("%d",&t);
while (t--) {
scanf("%d",&n);
for (i=1;i<=n;i++) scanf("%d",&a[i]);
bp=b;
root=maketree(1,n);
scanf("%d",&q);
while (q--) {
int t,l,r;
scanf("%d%d%d%d",&t,&l,&r,&x);
if (t==1) set1(root,1,n,l,r);
else set2(root,1,n,l,r);
}
godown(root,1,n);
for (i=1;i<=n;i++) printf("%d ",a[i]);
printf("\n");
}
return 0;
}