51nod 1642 区间欧拉函数

51nod 区间欧拉函数

链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1642

直觉离线。确实可以离线。
给定数组
a1,a2,a3,....,an
Q 询问。每次询问给定l,r计算:

φ(i=lrai)

因为

φ(Pk)=PkPk1 , k>0φ(1)=1

所以:
Pn 时:

φ(Pn)=Pφ(n)

Pn 时:

φ(Pn)=(P1)φ(n)

线段树离线处理即可。对询问按右端点排序

#include <stdio.h>
#include <string.h>
#include <algorithm>
#define MAXN 1000005
#define MAXNN 200005
using namespace std;
typedef long long LL;
struct Io
{
    char A[MAXN],*L,*R;
    Io()
    {
        L=R=A;
    }
    void Io_fread()
    {
        L=A;
        R=A+fread(A,sizeof(char),MAXN,stdin);
    }
    int read()
    {
        int tmp=0;
        if(L==R)
        {
            Io_fread();
            if(L==R)return tmp;
        }
        while(*L<'0'||*L>'9')
        {
            L++;
            if(L==R)
            {
                Io_fread();
                if(L==R)return tmp;
            }
        }
        while(*L>='0'&&*L<='9')
        {
            tmp=tmp*10+ *L-'0';
            L++;
            if(L==R)
            {
                Io_fread();
                if(L==R)return tmp;
            }
        }
        return tmp;
    }
}I;
const LL mod=1e9+7;
struct node
{
    int w;
    int c[2];
    int a;
    node()
    {
        a=1;
        c[0]=c[1]=0;
    }
};
struct Bt
{
    node A[MAXNN*3];
    int deep;
    int root;
    int size;
    Bt()
    {
        deep=2;
        root=1;
    }
    void _insert(int l,int r,int L,int R,int &k,int key)
    {
        if(R<l||L>r)return ;
        if(k==0)    k=deep++;
        node &P=A[k];
        if(l<=L&&R<=r)
        {
            P.a=(LL)P.a*key%mod;
            return;
        }
        int mid=(L+R)>>1;
        _insert(L,mid,L,mid,P.c[0],P.a);
        _insert(mid+1,R,mid+1,R,P.c[1],P.a);
        P.a=1;
        _insert(l,r,L,mid,P.c[0],key);
        _insert(l,r,mid+1,R,P.c[1],key);
    }
    void insert(int l,int r,int key)
    {
        _insert(l,r,0,size,root,key);
    }
    int _query(int x,int L,int R,int k)
    {
        if(x<L||x>R)return 1;
        if(L==R)    return A[k].a;
        node &P=A[k];
        int mid=(L+R)>>1;
        return (LL)_query(x,L,mid,P.c[0])*(LL)_query(x,mid+1,R,P.c[1])%mod*P.a%mod;
    }
    int query(int x)
    {
        return _query(x,0,size,root);
    }
}B;

struct edge
{
    int a;
    int k;
    int next;
    edge(){}
}E[MAXN*4];
int deep,inof[MAXN];
void add(int a,int P,int k)
{
    E[deep].a=P;
    E[deep].k=k;
    E[deep].next=inof[a];
    inof[a]=deep++;
}
int data[MAXNN];
int vis[MAXN],used[MAXN];

struct QQ
{
    int l,r,i;
    QQ(){}
    bool operator <(const QQ &a)const
    {
        return r<a.r;
    }
}Q[MAXNN];
int ans[MAXNN],tmp[MAXN];
int main ()
{
    //freopen("/Users/gaoxusheng/Desktop/In.txt","rw",stdin);
    memset(inof,-1,sizeof inof);
    int n;
    n=I.read();
    B.size=n;
    for(int i=1;i<=n;i++)
    {
        data[i]=I.read();
        vis[data[i]]=true;
    }
    for(int i=2;i<MAXN;i++)
    {
        if(used[i])continue;
        add(i,i,1);
        for(int j=i<<1;j<MAXN;j+=i)
        {
            used[j]=true;
            if(!vis[j])continue;
            int u=j,k=0;
            while(u%i==0)
            {
                k++;
                u/=i;
            }
            add(j,i,k);
        }
    }

    int q=I.read();
    for(int i=0;i<q;i++)
    {
        Q[i].l=I.read();
        Q[i].r=I.read();
        Q[i].i=i;
    }
    sort(Q,Q+q);
    for(int i=0,x=1;i<q;)
    {
        while(x<=Q[i].r)
        {
            for(int d=inof[data[x]];d>-1;d=E[d].next)
            {
                edge &e=E[d];
                B.insert(tmp[e.a]+1,x,e.a-1);
                if(tmp[e.a])B.insert(0,tmp[e.a],e.a);
                int k=1;
                while(k<e.k)
                {
                    B.insert(0,x,e.a);
                    k++;
                }
                tmp[e.a]=x;
            }
            x++;
        }
        int d=Q[i].r;
        while(i<q&&Q[i].r==d)
        {
            ans[Q[i].i]=B.query(Q[i].l);
            i++;
        }
    }
    for(int i=0;i<q;i++)printf("%d\n",ans[i]);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值