CodeForces - 1422F Boring Queries(主席树+线段树/RMQ)
題目鏈接:點擊查看
題目大意:給出 n 個數組成的數組 a ,再給出 m 次詢問,每次詢問需要回答區間 [ l , r ] 中所有元素的最小公倍數,強制在線
題目分析:首先考慮多個數的最小公倍數該如何求,因為每個質因子對于最小公倍數的貢獻都是相互獨立的,所以對于某個質因子 p 來說,可以求出其在所有數字中出現的次數記為 b[ 1 ] , b[ 2 ] ... b[ n ] ,那么質因子 p 對于最小公倍數的貢獻就是?,對于所有質因子的貢獻求乘積就是所求的最小公倍數了
因為每個元素只有 2e5 這么大,所以考慮開根號,令閾值等于 500,滿足 500 * 500 >= 2e5 ,其意義就是,在某個數字中,出現次數大于等于 2 的質因子的大小,一定不會大于 500,這樣一來我們就可以將所有的質因子分兩類單獨計算貢獻了:
對于第一種情況,因為 500 以內的質數只有 95 個,所以可以直接開 95 個線段樹去維護每個質因子的貢獻,維護一下區間最大值即可,對于第二種情況,統計區間內不同的質因子,不難想到使用主席樹維護,套上模板隨便改改就好了
這可能不是正解,因為遞歸式的線段樹寫 T 了,換成循環式的線段樹勉強劃過去了
2021.8.23 UPDATE:
用RMQ代替線段樹會跑的快好多,需要注意普通的數組是開不下的,需要換成char數組,只儲存冪次就可以了
2021.8.25 UPDATE:
利用主席樹做一個類似差分的功能,妙啊
?
代碼:
主席樹+線段樹
//#pragma GCC optimize(2) //#pragma GCC optimize("Ofast","inline","-ffast-math") //#pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<list> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e5+100;const int mod=1e9+7;int num[N],a[N],last[N<<1],n,seg_cnt; /*線段樹*/ struct Seg_tree {int mmax[262626];int base=131072;void build(){for(int i=0;i<n;i++)mmax[base+i]=num[i+1];for(int i=base-1;i>=1;i--)mmax[i]=max(mmax[i<<1],mmax[i<<1|1]);}int query(int k,int l,int r){l+=base;r+=base;l--;r--;int ans=0;while(l<=r){if(l&1){ans=max(ans,mmax[l]);l++;}if(~r&1){ans=max(ans,mmax[r]);r--;}l>>=1;r>>=1;}return ans;} }seg[105]; /*線段樹*/ /*主席樹*/ struct Node {int l,r;LL sum; }tree[N*40];int cnt,root[N];void update(int pos,int &k,int l,int r,LL val) {tree[cnt++]=tree[k];k=cnt-1;tree[k].sum=max(tree[k].sum,1LL)*val%mod;if(l==r)return;int mid=l+r>>1;if(pos<=mid)update(pos,tree[k].l,l,mid,val);elseupdate(pos,tree[k].r,mid+1,r,val); }LL query(int rt,int l,int r,int L,int R)//[l,r]:目標區間,[L,R]:當前區間 {if(R<l||L>r)return 1;if(L>=l&&R<=r)return max(tree[rt].sum,1LL);int mid=L+R>>1;return query(tree[rt].l,l,r,L,mid)*query(tree[rt].r,l,r,mid+1,R)%mod; }void init() {root[0]=0;tree[0].l=tree[0].r=tree[0].sum=0;cnt=1; } /*主席樹*/ /*快速冪+逆元*/ LL q_pow(LL a,LL b) {LL ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod;b>>=1;}return ans; }LL inv(LL num) {return q_pow(num,mod-2); } /*快速冪+逆元*/ /*埃氏篩*/ bool vis[N<<1];void P() {for(int i=2;i<=500;i++){if(vis[i])continue;for(int j=1;j<=n;j++){num[j]=1;while(a[j]%i==0){a[j]/=i;num[j]*=i;}}seg_cnt++;seg[seg_cnt].build();for(int j=i+i;j<N<<1;j+=i)vis[j]=true;} } /*埃氏篩*/ int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);init();scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",a+i);P();//到此為止剩下的a[i]都是大于500的素數了for(int i=1;i<=n;i++){root[i]=root[i-1];if(a[i]==1)continue;if(last[a[i]])update(last[a[i]],root[i],1,n,inv(a[i]));update(i,root[i],1,n,a[i]);last[a[i]]=i;}int m;scanf("%d",&m);LL last=0;while(m--){int l,r;scanf("%d%d",&l,&r);l=(l+last)%n+1;r=(r+last)%n+1;if(l>r)swap(l,r);LL ans=1;for(int i=1;i<=seg_cnt;i++)ans=ans*seg[i].query(1,l,r)%mod;ans=ans*query(root[r],l,r,1,n)%mod;printf("%lld\n",last=ans);}return 0; }RMQ+主席樹:
//#pragma GCC optimize(2) //#pragma GCC optimize("Ofast","inline","-ffast-math") //#pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<list> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e5+5;const int mod=1e9+7;int num[N],a[N],last[N<<1],Log[N],n,st_cnt; /*RMQ*/ struct RMQ {char st[N][18];int poww[20];void get_st(int x) {poww[0]=1;for(int i=1;i<=20;i++) {poww[i]=1LL*poww[i-1]*x%mod;}for(int i=1;i<=n;i++)st[i][0]=num[i];for(int i=1;i<=17;i++)for(int j=1;j+(1<<i)-1<=n;j++)st[j][i]=max(st[j][i-1],st[j+(1<<i-1)][i-1]);}int ask(int l,int r) {int k=Log[r-l+1];return poww[max(st[l][k],st[r-(1<<k)+1][k])];} }st[90]; /*RMQ*/ /*主席樹*/ struct Node {int l,r;LL sum; }tree[N*40];int cnt,root[N];void update(int pos,int &k,int l,int r,LL val) {tree[cnt++]=tree[k];k=cnt-1;tree[k].sum=max(tree[k].sum,1LL)*val%mod;if(l==r)return;int mid=l+r>>1;if(pos<=mid)update(pos,tree[k].l,l,mid,val);elseupdate(pos,tree[k].r,mid+1,r,val); }LL query(int rt,int l,int r,int L,int R)//[l,r]:目標區間,[L,R]:當前區間 {if(R<l||L>r)return 1;if(L>=l&&R<=r)return max(tree[rt].sum,1LL);int mid=L+R>>1;return query(tree[rt].l,l,r,L,mid)*query(tree[rt].r,l,r,mid+1,R)%mod; }void init() {for(int i=1;i<N;i++) {Log[i]=log2(i);}root[0]=0;tree[0].l=tree[0].r=tree[0].sum=0;cnt=1; } /*主席樹*/ /*快速冪+逆元*/ LL q_pow(LL a,LL b) {LL ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod;b>>=1;}return ans; }LL inv(LL num) {return q_pow(num,mod-2); } /*快速冪+逆元*/ /*埃氏篩*/ bool vis[N<<1];void P() {for(int i=2;i<=450;i++){if(vis[i])continue;for(int j=1;j<=n;j++){num[j]=0;while(a[j]%i==0){a[j]/=i;num[j]++;}}st_cnt++;st[st_cnt].get_st(i);for(int j=i+i;j<=450;j+=i)vis[j]=true;} } /*埃氏篩*/ int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);init();scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",a+i);P();//到此為止剩下的a[i]都是大于500的素數了for(int i=1;i<=n;i++){root[i]=root[i-1];if(a[i]==1)continue;if(last[a[i]])update(last[a[i]],root[i],1,n,inv(a[i]));update(i,root[i],1,n,a[i]);last[a[i]]=i;}int m;scanf("%d",&m);LL last=0;while(m--){int l,r;scanf("%d%d",&l,&r);l=(l+last)%n+1;r=(r+last)%n+1;if(l>r)swap(l,r);LL ans=1;for(int i=1;i<=st_cnt;i++)ans=ans*st[i].ask(l,r)%mod;ans=ans*query(root[r],l,r,1,n)%mod;printf("%lld\n",last=ans);}return 0; }主席樹:
// Problem: Boring Queries // Contest: Virtual Judge - CodeForces // URL: https://vjudge.net/problem/CodeForces-1422F // Memory Limit: 524 MB // Time Limit: 3000 ms // // Powered by CP Editor (https://cpeditor.org)// #pragma GCC optimize(2) // #pragma GCC optimize("Ofast","inline","-ffast-math") // #pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<list> #include<unordered_map> #define lowbit(x) (x&-x) using namespace std; typedef long long LL; typedef unsigned long long ull; template<typename T> inline void read(T &x) {T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f; } template<typename T> inline void write(T x) {if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0'); } const int inf=0x3f3f3f3f; const int N=2e5+100; const int mod=1e9+7; struct Node {int l,r;LL mul; }tree[N*150]; int mi[N],pre[N],root[N],cnt; int q_pow(int a,int b) {int ans=1;while(b) {if(b&1) ans=1LL*ans*a%mod;a=1LL*a*a%mod;b>>=1;}return ans; } void update(int &k,int pos,LL val,int l,int r) {tree[cnt++]=tree[k];k=cnt-1;tree[k].mul=tree[k].mul*val%mod;if(l==r) return;int mid=(l+r)>>1;if(pos<=mid) update(tree[k].l,pos,val,l,mid);else update(tree[k].r,pos,val,mid+1,r); } LL query(int k,int l,int r,int L,int R) {if(L>r||R<l) return 1;if(L>=l&&R<=r) return tree[k].mul;int mid=(L+R)>>1;return query(tree[k].l,l,r,L,mid)*query(tree[k].r,l,r,mid+1,R)%mod; } void init() {for(int i=2;i<N;i++) {if(!mi[i]) {for(int j=i;j<N;j+=i) {mi[j]=i;}}}root[0]=0;tree[0].l=tree[0].r=0;tree[0].mul=1;cnt=1; } int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);init();int n;scanf("%d",&n);for(int i=1,x;i<=n;i++) {root[i]=root[i-1];vector<pair<int,int>>redo;read(x);while(x>1) {int p=mi[x],inv=q_pow(p,mod-2),k=1;while(x%p==0) {x/=p,k*=p;if(pre[k]) redo.push_back({pre[k],inv});pre[k]=i;}update(root[i],i,k,1,n);}LL res=1;for(int j=0;j<(int)redo.size();j++) {if(j==0||redo[j].first!=redo[j-1].first) {res=1;}res=res*redo[j].second%mod;if(j+1==(int)redo.size()||redo[j].first!=redo[j+1].first) {update(root[i],redo[j].first,res,1,n);}}}int ans=0,m;read(m);while(m--) {int l,r;read(l),read(r);l=(ans+l)%n+1,r=(ans+r)%n+1;if(l>r) {swap(l,r);}printf("%d\n",ans=query(root[r],l,r,1,n));}return 0; }總結
以上是生活随笔為你收集整理的CodeForces - 1422F Boring Queries(主席树+线段树/RMQ)的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: ZOJ - 2676 Network W
 - 下一篇: CodeForces - 1422E M