1. 程式人生 > >hdu 6273 Master of GCD (線段樹+區間更新)

hdu 6273 Master of GCD (線段樹+區間更新)

Problem J. Master of GCD
Hakase has n numbers in a line. At first, they are all equal to 1. Besides, Hakase is interested in primes. She will choose a continuous subsequence [l,r] and a prime parameter x each time and for every l ≤ i ≤ r, she will change ai into ai ∗x. To simplify the problem, x will be 2 or 3. After m operations, Hakase wants to know what is the greatest common divisor of all the numbers.
Input The first line contains an integer T (1 ≤ T ≤ 10) representing the number of test cases. For each test case, the first line contains two integers n (1 ≤ n ≤ 100000) and m (1 ≤ m ≤ 100000), where n refers to the length of the whole sequence and m means there are m operations. Thefollowingmlines,eachlinecontainsthreeintegersli (1 ≤ li ≤ n), ri (1 ≤ ri ≤ n), xi (xi ∈{2,3}), which are referred above.
Output For each test case, print an integer in one line, representing the greatest common divisor of the sequence. Due to the answer might be very large, print the answer modulo 998244353.
Example
standard input

2

5 3

1 3 2

3 5 2

1 5 3

6 3

1 2 2

5 6 2

1 6 2

standard output

6

2
Explanation Forthefirsttestcase, afteralloperations, thenumberswillbe [6,6,12,6,6]. Sothegreatestcommon divisor is 6.
 


題意:有一個長度位n,值全為1的區間。進行m次操作,每次將區間[l,r]的值都乘上2或則3。最後求區間[l,r]的最大公約數。結果可能會很大,需要將答案對998244353取模。

思路:涉及到區間更新和查詢問題都可以用線段樹做,如果用線段樹維護gcd,就有一個問題,我們需要對值進行取模,取模後的gcd發生了改變,所以不可行。仔細閱讀題目,發現每次區間只能乘上2或則3。因此我們可以用線段樹維護2的個數和3的個數(維護的其實是最大公約數的因子)。父親區間的2或3的個數為兒子區間較少的2或3的個數。

最後的答案ans=pow(2,2的個數)*pow(3,3的個數);

區間更新需要用到延遲標記。

AC程式碼:

//線段樹維護2的數目和3的數目
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN =1e5+10;
const ll MOD = 998244353;
const ll INF = 0x3f3f3f3f;
int N,M;

ll power(ll a,ll b){
	ll ans=1;
	a%=MOD;
	while(b){
		if(b&1){
			ans=ans*a%MOD;
			b--;
		}
		b>>=1;
		a=a*a%MOD;
	}
	return ans;
}

struct node{
	int l,r;
	ll sum2,sum3,lazy2,lazy3;
	
	void update(ll num2,ll num3){
		sum2+=num2;
		lazy2+=num2;
		sum3+=num3;
		lazy3+=num3;
	}
	
}tree[MAXN*4];
ll a[MAXN];



void push_up(int x){
	tree[x].sum2=min(tree[x<<1].sum2,tree[x<<1|1].sum2);
	tree[x].sum3=min(tree[x<<1].sum3,tree[x<<1|1].sum3);
}

void push_down(int x){
	ll lazyval2=tree[x].lazy2;
	ll lazyval3=tree[x].lazy3;
	if(lazyval2!=0 || lazyval3!=0){
		tree[x<<1].update(lazyval2,lazyval3);
		tree[x<<1|1].update(lazyval2,lazyval3);
		tree[x].lazy2=0;
		tree[x].lazy3=0;
	}
}

void build(int x,int l,int r){
	tree[x].l=l;tree[x].r=r;
	tree[x].lazy2=tree[x].sum2=0;
	tree[x].lazy3=tree[x].sum3=0;
	if(l==r){
		tree[x].sum2=0;
		tree[x].sum3=0;
		return ;
	}
	int mid=(l+r)/2;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
	push_up(x);
}

void update(int x,int l,int r,ll num2,ll num3){
	int L=tree[x].l,R=tree[x].r;
	if(l<=L && R<=r){
		tree[x].update(num2,num3);
		return ;
	}
	push_down(x);
	int mid=(L+R)/2;
	if(mid>=l)
		update(x<<1,l,r,num2,num3);
	if(mid<r)
		update(x<<1|1,l,r,num2,num3);
	push_up(x);
}

void query(int x,int l,int r,ll &sum2,ll &sum3){
	int L=tree[x].l,R=tree[x].r;
	if(l<=L && R<=r){
		sum2=min(sum2,tree[x].sum2);
		sum3=min(sum3,tree[x].sum3);
		return;
	}
	push_down(x);
	int mid=(L+R)/2;
	if(mid>=l)
		query(x<<1,l,r,sum2,sum3);
	if(mid<r)
		query(x<<1|1,l,r,sum2,sum3);
}

int main(){
	int T,l,r;
	ll num;
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&N,&M);
		build(1,1,N);
		while(M--){
			scanf("%d%d%lld",&l,&r,&num);
			if(num==2)
				update(1,l,r,1,0);
			else
				update(1,l,r,0,1);
		}
		ll num2=INF,num3=INF;
		query(1,1,N,num2,num3);
		ll ans=power(2,num2)*power(3,num3)%MOD;
		printf("%lld\n",ans);
	}
	return 0;
}