bzoj 5334 & 洛谷4588 [Tjoi2018]数学计算 题解(线段树,打死你也想不到是用线段树)

33 篇文章 0 订阅

原题链接:
bzoj
洛谷

题意简述

你有一个数 x x x,支持两种操作:
1 m:执行x*=m,并输出x%modlong long能存下,mod不一定为质数
2 posx/=第pos次乘的m,保证第pos次是1操作,输出x%mod
处理一些这样的操作。

思路

1操作很好做。2操作。。。看起来就是维护一个数组存一下每次乘了几,然后除对应位置的数即珂。

珂是,什么阻挡了我们的计算?

  1. 要膜
  2. 膜数mod不一定是质数!(所以没法用逆元)

f ∗ ∗ k f**k fk。所以我们要另外想一个办法。我们还是维护那个数组,对于除的操作,我们就把第 p o s pos pos个位置改成 1 1 1,对于乘的操作,我们就把第 i i i个位置改成 m m m i i i表示这次操作是第 i i i次操作),然后输出的时候,就询问整体的和即珂。

那么如何加速询问整体的和呢?线段树。
然后这个题就变成了一个单点修改,整体查询的水题了。由于是整体查询,你甚至不用写 Q u e r y Query Query函数,只要输出线段树上第一个位置的 s u m sum sum值即珂。

代码:

#include<bits/stdc++.h>
using namespace std;
namespace Flandle_Scarlet
{
    #define N 100100
    #define int long long
    int q,mod;
 
    void R1(int &x)
    {
        x=0;char c=getchar();int f=1;
        while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
        while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=(f==1)?x:-x;
    }
    void Input()
    {
        R1(q),R1(mod);
    }
 
    class SegmentTree
    {
        public:
            struct node
            {
                int l,r;
                int s;
            }tree[N<<2];
 
            #define ls index<<1
            #define rs index<<1|1
 
            #define L tree[index].l
            #define R tree[index].r
            #define S tree[index].s
 
            #define lL tree[ls].l
            #define lR tree[ls].r
            #define lS tree[ls].s
 
            #define rL tree[rs].l
            #define rR tree[rs].r
            #define rS tree[rs].s
 
            void Update(int index)
            {
                S=(lS*rS)%mod;
            }
            void BuildTree(int l,int r,int index)
            {
                L=l,R=r,S=1;
                if (l==r) return;
                int mid=(l+r)>>1;
                BuildTree(l,mid,ls);
                BuildTree(mid+1,r,rs);
                Update(index);
            }
            void Change1(int pos,int x,int index)
            {
                if (pos<L or R<pos) return;
                if (L==R) return (void)(S=x%mod);
                Change1(pos,x,ls);
                Change1(pos,x,rs);
                Update(index);
            }
    }T;
    int ccnt=0;//change cnt
    vector<int>changes;//positions of changes
    void Soviet()
    {
        T.BuildTree(1,q,1);
        for(int i=1;i<=q;++i)
        {
            int o;R1(o);
            if (o==1)
            {
                int m;R1(m);
                m%=mod;
                T.Change1(i,m,1);
                printf("%lld\n",T.tree[1].s%mod);
            }
            else if (o==2)
            {
                int pos;R1(pos);
                T.Change1(pos,1,1);
                printf("%lld\n",T.tree[1].s%mod);
            }
        }
    }
 
    void IsMyWife()
    {
        if (0)
        {
            freopen("","r",stdin);
            freopen("","w",stdout);
        }
        int t;R1(t);
        while(t--)
        {
            Input();
            Soviet();
        }
    }
    #undef int //long long
};
int main()
{
    Flandle_Scarlet::IsMyWife();
    return 0;
}

回到总题解界面

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值