“美登杯”上海市高校大学生程序设计 E. 小花梨的数组 (线段树)
https://acm.ecnu.edu.cn/contest/173/problem/E/
分析:
考虑这样一种情况,如果对一个点连续地做几次乘操作,那么之后紧跟着的除操作只需要将乘操作的次数减少即可。(因为如果当前是乘于的最小素因子后面肯定也是除上这个)
那么对这个点的操作将会变成连续的一段乘或者除。如果一段除操作之后出现了乘操作,那只能在一段除之后做一段乘操作了,因为执行了除之后minprime可能会变化。(很显然)
所以最后对这个点的操作将会变成一段除操作跟着一段乘操作。
那么就可以利用线段树维护这样一段操作的除乘的个数了。线段树每个节点维护两个信息:除操作个数,乘操作个数
收获:对线段树的强大操作再一次的认识了!
#include<bits/stdc++.h> using namespace std; #define lc ((o) << 1) #define rc ((o) << 1 | 1) #define ll long long const int N = 100010; const int MOD = 1e9+7; int Mul[N<<2],Div[N<<2],a[N]; void powndown(int o , int l , int r) { if(Mul[o] || Div[o]) { if(Mul[lc]>=Div[o]) { Mul[lc]-=Div[o]; } else { Div[lc]+=(Div[o]-Mul[lc]); Mul[lc]=0; } if(Mul[rc]>=Div[o]) { Mul[rc]-=Div[o]; } else { Div[rc]+=(Div[o]-Mul[rc]); Mul[rc]=0; } Mul[lc]+=Mul[o]; Mul[rc]+=Mul[o]; Mul[o]=Div[o]=0; } } void update(int o, int l, int r, int L, int R, int tree[], int op) { if(L <= l && R >= r) { if(op == 1)tree[o]++; else { if(Mul[o])Mul[o]--; else tree[o]++; } return; } powndown(o, l, r); int m = (l + r) / 2; if(L <= m)update(lc, l, m, L, R, tree, op); if(R > m)update(rc, m + 1, r, L, R, tree, op); } void query(int o, int l, int r, int x, int& divnum, int& mulnum) { if(l == r) { divnum = Div[o]; mulnum = Mul[o]; return; } powndown(o, l, r); int m = (l + r) / 2; if(x <= m)query(lc, l, m, x, divnum, mulnum); else query(rc, m + 1, r, x, divnum, mulnum); } int tot; bool vis[N]; int pr[N]; void init() { tot=0; for(int i=2 ; i<=N ; i++) { if(vis[i]==0) { pr[++tot]=i; //cout<<i<<" "<<pr[10]<<endl; for(int j=2*i;j<=N;j+=i) vis[j]=1; } } } vector<int>FA[N]; ll POW(ll x , ll y) { ll ans=1; while(y) { if(y&1) ans=ans*x%MOD; y>>=1; x=x*x%MOD; } return ans; } int main() { int n,m;scanf("%d%d",&n,&m); init(); //cout<<pr[1]<<" "<<pr[2]<<endl; for(int i=1 ; i<=n ; i++) { scanf("%d",&a[i]); int x=a[i]; for(int j=1 ; j<=tot&&pr[j]*pr[j]<=x;j++) { while(x%pr[j]==0) { x/=pr[j]; FA[i].push_back(pr[j]); } } if(x!=1) FA[i].push_back(x); // cout<<FA[i].size()<<endl; } while(m--) { int op,l,r;scanf("%d",&op); if(op==1) { scanf("%d%d",&l,&r); update(1,1,n,l,r,Mul,1); } else if(op==2) { scanf("%d%d",&l,&r); update(1,1,n,l,r,Div,2); } else { scanf("%d",&l); int numMul=0,numDiv=0; query(1,1,n,l,numDiv,numMul); // cout<<numDiv<<" "<<numMul<<endl; // cout<<FA[l].size()<<endl; if(numDiv>=FA[l].size()) { puts("1"); } else { ll ans=1,tmp=FA[l][numDiv]; for(int i=numDiv ; i<FA[l].size();i++) ans=(ans*(1ll*FA[l][i]))%MOD; ans=(ans*POW(tmp,numMul))%MOD; printf("%lld\n",ans); } } } }