题意:初始序列为1,两种操作,一种区间所有数 * 2, 一种是区间所有数 * 3 ,问最后所有数的最大公约数
题解:区间乘+区间GCD肯定不对,因为有取模操作,对乘积结果取模再求GCD肯定不对了
然后就想到维护每个结点乘2的次数和乘3的次数,分别取最小值就好了 ,ans=*,x,y分别是区间最小2的个数和3的个数
线段树区间修改+最小值
细节:快速幂记得开 LL,中间会爆int
#include <bits/stdc++.h> #define ll long long using namespace std; const int maxn = 1e5 + 5; const int INF = 0x3f3f3f3f; const int mod = 998244353; int sum2[maxn*4],lazy2[maxn*4]; int sum3[maxn*4],lazy3[maxn*4]; void pushdown(int l,int r,int p,int sum[],int lazy[]){ int mid=(l+r)/2; int pp=p; if(lazy[p]){ sum[p<<1]+=lazy[p]; sum[p<<1|1]+=lazy[p]; lazy[p<<1]+=lazy[p]; lazy[p<<1|1]+=lazy[p]; lazy[p]=0; } } void build(int l, int r,int p){ sum2[p]=sum3[p]=0; lazy2[p]=lazy3[p]=0; if(l==r){ return ; } int mid=(l+r)/2; build(l,mid,p<<1); build(mid+1,r,p<<1|1); } void update(int l,int r,int L,int R,int p,int sum[],int lazy[]){ if(L<=l&&r<=R){ sum[p]+=1; lazy[p]+=1; return ; } pushdown(l,r,p,sum,lazy); int mid=(l+r)/2; if(L<=mid) update(l,mid,L,R,p<<1,sum,lazy); if(R>mid) update(mid+1,r,L,R,p<<1|1,sum,lazy); sum[p]=min(sum[p<<1],sum[p<<1|1]); } int query(int l,int r,int L,int R,int p,int sum[],int lazy[]){ if(L<=l&&r<=R){ return sum[p]; } pushdown(l,r,p,sum,lazy); int mid=(l+r)/2; int ans=INF; if(L<=mid) ans=min(ans,query(l,mid,L,R,p<<1,sum,lazy)); if(R>mid) ans=min(ans,query(mid+1,r,L,R,p<<1|1,sum,lazy)); return ans; } ll pow(ll a,int b){ ll ans=1; while(b){ if(b&1) ans=ans*a%mod; a=a*a%mod; b=b/2; } return ans%mod; } int main(){ int t; scanf("%d",&t); while(t--){ int n; scanf("%d",&n); int m; scanf("%d",&m); build(1,n,1); while(m--){ int l,r,x; scanf("%d%d%d",&l,&r,&x); if(x==2) update(1,n,l,r,1,sum2,lazy2); else update(1,n,l,r,1,sum3,lazy3); } int xx=query(1,n,1,n,1,sum2,lazy2); int yy=query(1,n,1,n,1,sum3,lazy3); ll ans=pow(2*1ll,xx)*pow(3*1ll,yy)%mod; printf("%lld\n",ans); } return 0; } /* 2 5 3 1 3 2 3 5 2 1 5 3 6 3 1 2 2 5 6 2 1 6 2 */