power oj 2821: 小Y學長的GCD難題(線段樹區間求最大公因數+區間修改)
阿新 • • 發佈:2019-01-30
Description
小Y:給你一個序列a,你會計算a[l]到a[r]的GCD嗎?
小Z:這不是sb題嗎?
小Y:如果給你q次詢問呢?
小Z:還是很簡單啊!!!
小Y:如果我可以修改某個區間的值為同一個值呢?
小Z:這尼瑪能做???
........
你能幫助小Z計算出區間l到r的GCD嗎?
Input
第一行輸入一個TT(1≤T≤51≤T≤5),接下來有T組測試。 對於每一組測試: 第一行輸入nn,qq(∑n≤2×105∑n≤2×105,∑q≤2×105∑q≤2×105),表示序列aa的長度和詢問次數 第二行nn個整數aiai(1≤ai≤231−11≤ai≤231−1),表示序列aa的初始值。 接下來qq行,每行代表一個操作: 操作1:1 l r x (1≤l,r≤n,1≤231−11≤l,r≤n,1≤231−1)表示將區間[l,r][l,r]內的所有數全部修改為xx 操作2:2 l r (1≤l,r≤n1≤l,r≤n)表示詢問區間[l,r][l,r]的GCD
Output
每行輸出一個整數表示答案
1 4 3 2 3 6 9 2 1 4 1 1 1 3 2 1 4
1 3
PS:線段樹的裸題,注意細節。
AC程式碼:
#include <iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<map> #include<queue> #include<set> #include<cmath> #include<stack> #include<string> const int maxn=2e5+10; const int mod=1e9+7; const int inf=1e8; #define me(a,b) memset(a,b,sizeof(a)) typedef long long ll; using namespace std; int d[maxn<<2],lazy[maxn<<2]; int gcd(int a,int b) { if(!b) return a; return gcd(b,a%b); } void update(int rt) { d[rt]=gcd(d[rt<<1],d[rt<<1|1]); } void build(int l,int r,int rt) { if(l==r) { scanf("%d",&d[rt]); return ; } int m=(l+r)>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1); update(rt); } void pushdown(int rt) { if(lazy[rt]) { d[rt<<1]=d[rt<<1|1]=lazy[rt]; lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt]; lazy[rt]=0; } } void pushdate(int L,int R,int c,int l,int r,int rt) { if(L<=l&&R>=r) { d[rt]=lazy[rt]=c; return ; } pushdown(rt); int m=(l+r)>>1; if(L<=m) pushdate(L,R,c,l,m,rt<<1); if(R>m) pushdate(L,R,c,m+1,r,rt<<1|1); update(rt); } int getgcd(int L,int R,int l,int r,int rt) { if(L<=l&&R>=r) return d[rt]; pushdown(rt); int m=(l+r)>>1; int a=0,b=0; if(L<=m) a=getgcd(L,R,l,m,rt<<1); if(R>m) b=getgcd(L,R,m+1,r,rt<<1|1); return gcd(a,b); } int main() { int t;cin>>t; while(t--) { int n,q; cin>>n>>q; me(d,0),me(lazy,0); build(1,n,1); while(q--) { int x,a,b,c; scanf("%d",&x); if(x==1) { scanf("%d%d%d",&a,&b,&c); pushdate(min(a,b),max(a,b),c,1,n,1); } else { scanf("%d%d",&a,&b); printf("%d\n",getgcd(min(a,b),max(a,b),1,n,1)); } } } return 0; }