• 【清华集训2014】奇数国 题解(线段树+欧拉函数)


    题目链接

    题目大意:给出一段长度为$100000$的初始值为$3$的序列。有两种操作:1.把$a_x$的值改为$y$;2.求$varphi (prod _{i=l}^r a_i)mod 19961993$的值。

    -----------------------------------

    题目比较显然,可以用线段树维护区间积。

    欧拉函数的通式:$varphi (n)=n*(1-frac{p_1-1}{p_1})*(1-frac{p_2-1}{p_2})*cdots *(1-frac{p_k-1}{p_k}),n=p_1^{c_1}*p_2^{c_2}*cdots *p_k^{c_k}$。

    根据题意,我们可以打表出质数表和逆元表。

    线段树维护一个$tag$,用来压位$sum$的质因子。需要的时候直接位运算统计答案即可。

    时间复杂度$O(q(60+log n))$。

    PS:考试的时候我怎么这么傻逼,没写逆元模数直接GG。数据结构也写的一坨屎……

    代码:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int mod=19961993;
    int prime[65]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281};
    int inv[65]={0,9980997,6653998,11977196,8555140,5444180,1535538,10568114,14708837,3471651,11701858,17386252,1618540,16066970,2321162,18263100,16948862,12518538,15380552,10725847,1686929,13399146,17182475,12025297,15924736,13582387,395287,6395590,15857658,16299242,6359573,3300802,18742940,6702567,10914471,16210746,11765678,5340151,18247466,7769638,8077107,11932588,6506948,1985748,6619521,5877135,4413707,9744480,10115270,14597757,16475182,18334191,5011379,18885205,7555336,621385,11309266,12170137,12006660,18304499,11153142};
    int q;
    struct node
    {
        int index,l,r,sum,tag;
    }tree[500005];
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void pushup(int index)
    {
        tree[index].sum=tree[index*2].sum*tree[index*2+1].sum%mod;
        tree[index].tag=tree[index*2].tag|tree[index*2+1].tag; 
    }
    inline void build(int index,int l,int r)
    {
        tree[index].l=l;
        tree[index].r=r;
        if (l==r)
        {
            tree[index].sum=3;
            tree[index].tag=2;
            return;
        }
        int mid=(l+r)>>1;
        build(index*2,l,mid);
        build(index*2+1,mid+1,r);
        pushup(index);
    }
    inline void update(int index,int pos,int x)
    {
        if (tree[index].l==tree[index].r)
        {
            tree[index].sum=x;
            tree[index].tag=0;
            for (int i=1;i<=60;i++)
                if (!(x%prime[i])) tree[index].tag|=1ll<<(i-1);
            return;
        }
        int mid=(tree[index].l+tree[index].r)>>1;
        if (pos<=mid) update(index*2,pos,x);
        else update(index*2+1,pos,x);
        pushup(index);
    }
    inline pair<int,int> query(int index,int l,int r)
    {
        if (l<=tree[index].l&&tree[index].r<=r) return make_pair(tree[index].sum,tree[index].tag);
        int mid=(tree[index].l+tree[index].r)>>1;pair<int,int> res;res.first=1;res.second=0;
        if (l<=mid)
        {
            pair<int,int> sum=query(index*2,l,r);
            res.first=res.first*sum.first%mod;
            res.second|=sum.second;
        }
        if (r>mid)
        {
            pair<int,int> sum=query(index*2+1,l,r);
            res.first=res.first*sum.first%mod;
            res.second|=sum.second;
        }
        return res;
    }
    inline int calc(int x,int tag)
    {
        int ans=x;
        for (int i=1;i<=60;i++) if (tag&(1ll<<(i-1))) ans=ans*inv[i]%mod*(prime[i]-1)%mod;
        return ans;
    } 
    signed main()
    {
        q=read();
        build(1,1,100000);
        for (int i=1;i<=q;i++)
        {
            int opt=read(),l=read(),r=read();
            if (opt==1) update(1,l,r);
            else{
                pair<int,int> ans=query(1,l,r);
                printf("%lld
    ",calc(ans.first,ans.second));
            }
        }
        return 0;
    }
  • 相关阅读:
    8.5 day8
    8.1 day6
    课后作业 day29
    博客整理day29
    博客整理day28
    博客整理day27
    博客整理day26
    课后作业 day26
    Python 学习day22
    课后作业 day21
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/13363226.html
Copyright © 2020-2023  润新知