“美登杯”上海市高校大学生程序设计 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);
            }
        }
    }
}
View Code

 

posted @ 2019-05-20 21:39  shuai_hui  阅读(124)  评论(0编辑  收藏  举报