传送门:Vjudge
题目描述:
There is a hard data structure problem in the contest:
There are n numbers a_1,a_2,...,a_n on a line, everytime you can change every number in a
segment [l,r] into a number x(type 1), or change every number a_i in a segment [l,r] which is
bigger than x to gcd(a_i,x) (type 2).
You should output the final sequence.
输入:
1
10
16807 282475249 1622650073 984943658 1144108930 470211272 101027544 1457850878 1458777923 2007237709
10
1 3 6 74243042
2 4 8 16531729
1 3 4 1474833169
2 1 8 1131570933
2 7 9 1505795335
2 3 7 101929267
1 4 10 1624379149
2 2 8 2110010672
2 6 7 156091745
1 2 5 937186357
输出:
16807 937186357 937186357 937186357 937186357 1 1 1624379149 1624379149 1624379149
一道诈骗题??
刚开始看到这道题很显然会发现这是一道区间修改+区间查询的题目.应该是由线段树进行操作的.但是看到区间gcd的时候,我想了一下.显然对于我们的区间修改来说,我们可以打一个 l a z y _ t a g lazy\_tag lazy_tag即可
当我们进行区间gcd的时候,我们会发现我们需要区间的最大值(这样可以很好的进行剪枝操作),所以我们可以维护区间最大值.假设此时我们的区间存在 l a z y _ t a g lazy\_tag lazy_tag,那么相当于这个区间所有的数字都是相同的,此时我们进行区间gcd十分的容易,直接改一下当前根的值以及lazy_tag的值即可.
但是刚开始让我陷入疑问的是当我们没有 l a z y _ t a g lazy\_tag lazy_tag的时候,我们进行区间gcd的话就意味着需要逐个逐个进行单点修改,就是 n n n的复杂度,这样的话假设我们所有的修改都是区间gcd的话,线段树的复杂度可能达到 n ∗ q n*q n∗q,似乎会被卡??
然而我们会发现一个有意思的点就是,我们进行区间gcd需要满足当前的区间的最大值大于我们的x.对于 g c d ( a , b ) ( a > b ) gcd(a,b)(a>b) gcd(a,b)(a>b),存在这样的一个规律, g c d ( a , b ) < a / 2 gcd(a,b)<a/2 gcd(a,b)<a/2.并且我们的数字最大是 2 32 2^{32} 232,这就意味着我们一直进行gcd操作最多也只需要32次(实际上没有32次).就变成了1,对于1来说,再进行gcd操作就可以直接剪枝掉了.所以我们的复杂度就可以优化了很大一部分(完整的均摊复杂度我不会算,但是可以凭感觉想一下QAQ).并且此题的时限为 1.5 s 1.5s 1.5s.所以线段树还是能通过本题的.
下面是具体的代码部分:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 100010
const double eps=1e-8;
#define int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
struct Segment_tree{
int l,r,mx,lazy;
}tree[maxn*4];
int n,m;int a[maxn];
int gcd(int aa,int bb) {
if(aa%bb==0) return bb;
else return gcd(bb,aa%bb);
}
void build(int l,int r,int rt) {
tree[rt].l=l;tree[rt].r=r;
if(l==r) {
tree[rt].mx=a[l];
return ;
}
int mid=(l+r)>>1;
build(lson);build(rson);
tree[rt].mx=max(tree[ls].mx,tree[rs].mx);
}
void pushdown(int rt) {
tree[ls].lazy=tree[ls].mx=tree[rt].lazy;
tree[rs].lazy=tree[rs].mx=tree[rt].lazy;
tree[rt].lazy=0;
}
void update1(int l,int r,int rt,int v) {
if(tree[rt].l==l&&tree[rt].r==r) {
tree[rt].lazy=tree[rt].mx=v;
return ;
}
if(tree[rt].lazy) pushdown(rt);
int mid=(tree[rt].l+tree[rt].r)>>1;
if(r<=mid) update1(l,r,ls,v);
else if(l>mid) update1(l,r,rs,v);
else update1(l,mid,ls,v),update1(mid+1,r,rs,v);
tree[rt].mx=max(tree[ls].mx,tree[rs].mx);
}
void update2(int l,int r,int rt,int v) {
if(tree[rt].mx<=v) return ;
if(tree[rt].l==l&&tree[rt].r==r) {
if(tree[rt].lazy) {
tree[rt].lazy=tree[rt].mx=gcd(tree[rt].mx,v);
return ;
}else {
if(tree[rt].l==tree[rt].r) {
tree[rt].lazy=tree[rt].mx=gcd(tree[rt].mx,v);
return ;
}
}
}
if(tree[rt].lazy) pushdown(rt);
int mid=(tree[rt].l+tree[rt].r)>>1;
if(r<=mid) update2(l,r,ls,v);
else if(l>mid) update2(l,r,rs,v);
else update2(l,mid,ls,v),update2(mid+1,r,rs,v);
tree[rt].mx=max(tree[ls].mx,tree[rs].mx);
}
void query(int l,int r,int rt) {
if(tree[rt].l==tree[rt].r) {
printf("%d ",tree[rt].mx);
return ;
}
if(tree[rt].lazy) pushdown(rt);
int mid=(l+r)>>1;
query(lson);query(rson);
}
int main() {
int T;T=read();
while(T--) {
memset(tree,0,sizeof(tree));
n=read();
for(int i=1;i<=n;i++) a[i]=read();
build(root);
m=read();
for(int i=1;i<=m;i++) {
int opt=read();
if(opt==1) {
int l=read(),r=read(),x=read();
update1(l,r,1,x);
}else {
int l=read(),r=read(),x=read();
update2(l,r,1,x);
}
}
query(root);
cout<<endl;
}
return 0;
}