生活随笔
收集整理的這篇文章主要介紹了
线段树区间gcd
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
小陽的貝殼
題意:
操作 1 l 到 r 的區間加上x
操作2 l到 r 相鄰兩個差值的絕對值最大 l==r輸出0
操作3 l 到 r 的gcd
難點就是是gcd 要想求區間能修改的gcd 你必須要知道一些知識
gcd(a,b)=gcd(a,b-a). gcd(a,b,c)=gcd(a,b-a,c-a) 以此類推
然后只要線段樹 維護 相鄰兩個的差值就可以了 當遇到 操作1
時 由于一個區間的加上相同的數 只有 第一個 和最后一個值改變了因此只有單點修改第一個 與最后一個就行了 即 第一個加上x 最后一個的下一個減去x
代碼
#include<bits/stdc++.h>
using namespace std
;
const int N
=1e5+7;
int n
,Q
,p
[N
],h
[N
];
int add
[N
];int gcd(int a
,int b
){return b
?gcd(b
,a
%b
):a
;}struct node
{int v
,g
,maxn
;
}tree
[4*N
];#define lson 2*node
#define rson 2*node+1
#define m (l+r)/2void build(int l
,int r
,int node
){if(l
==r
){tree
[node
].v
=p
[l
];tree
[node
].g
=h
[l
];tree
[node
].maxn
=h
[l
];return;}build(l
,m
,lson
);build(m
+1,r
,rson
);tree
[node
].g
=gcd(tree
[lson
].g
,tree
[rson
].g
);tree
[node
].maxn
=max(abs(tree
[lson
].maxn
),abs(tree
[rson
].maxn
));
}void push_down(int node
){if(add
[node
]){tree
[lson
].v
+=add
[node
];tree
[rson
].v
+=add
[node
];add
[lson
]+=add
[node
];add
[rson
]+=add
[node
];add
[node
]=0;}
}void update(int v
,int ql
,int qr
,int l
,int r
,int node
){if(ql
<=l
&&qr
>=r
){tree
[node
].v
+=v
;add
[node
]+=v
;return;}push_down(node
);if(ql
<=m
)update(v
,ql
,qr
,l
,m
,lson
);if(qr
>m
)update(v
,ql
,qr
,m
+1,r
,rson
);
}void upgcd(int v
,int pos
,int l
,int r
,int node
){if(l
==r
){tree
[node
].g
+=v
;tree
[node
].maxn
+=v
;return;}if(pos
<=m
)upgcd(v
,pos
,l
,m
,lson
);else upgcd(v
,pos
,m
+1,r
,rson
);tree
[node
].g
=gcd(tree
[lson
].g
,tree
[rson
].g
);tree
[node
].maxn
=max(abs(tree
[lson
].maxn
),abs(tree
[rson
].maxn
));
}int query(int ql
,int qr
,int l
,int r
,int node
){if(ql
<=l
&&qr
>=r
) return tree
[node
].g
;int ans
=0;if(ql
<=m
)ans
=gcd(ans
,query(ql
,qr
,l
,m
,lson
));if(qr
>m
)ans
=gcd(ans
,query(ql
,qr
,m
+1,r
,rson
));return ans
;
}
int querymax(int ql
,int qr
,int l
,int r
,int node
){if(ql
>qr
)return 0;if(ql
<=l
&&qr
>=r
){return abs(tree
[node
].maxn
);}int ans
=0;if(ql
<=m
)ans
=max(ans
,querymax(ql
,qr
,l
,m
,lson
));if(qr
>m
)ans
=max(ans
,querymax(ql
,qr
,m
+1,r
,rson
));return ans
;
}int queryvalue(int pos
,int l
,int r
,int node
){if(l
==r
)return tree
[node
].v
;push_down(node
);if(pos
<=m
)return queryvalue(pos
,l
,m
,lson
);return queryvalue(pos
,m
+1,r
,rson
);
}int main(){scanf("%d%d",&n
,&Q
);for(int i
=1;i
<=n
;i
++){scanf("%d",&p
[i
]);h
[i
]=p
[i
]-p
[i
-1];}build(1,n
,1);int q
,l
,r
,x
;while(Q
--){scanf("%d%d%d",&q
,&l
,&r
);if(q
==1){scanf("%d",&x
);update(x
,l
,r
,1,n
,1);upgcd(x
,l
,1,n
,1);if(r
+1<=n
)upgcd(-x
,r
+1,1,n
,1);}else if(q
==2){printf("%d\n",querymax(l
+1,r
,1,n
,1));}else if(q
==3){if(l
==r
)printf("%d\n",queryvalue(l
,1,n
,1));else{int ans
=queryvalue(l
,1,n
,1);ans
=gcd(ans
,query(l
+1,r
,1,n
,1));printf("%d\n",abs(ans
));}}}
}
總結
以上是生活随笔為你收集整理的线段树区间gcd的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。