P4588 [TJOI2018] 数学计算

题目描述
小豆现在有一个数 x,初始值为
1。小豆有 Q 次操作,操作有两种类型:
1 m:将 x 变为 ×*m,并输出 xmodM。
2 pos:将 x 变为 x 除以第 pos 次操作所乘的数(保证第 pos 次操作一定为类型 1,对于每一个类型 1 的操作至多会被除一次),并输出 xmodM。
输入格式
一共有 t 组输入。对于每一组输入,第一行是两个数字,Q,M。接下来 Q 行,每一行为操作类型 op,操作编号或所乘的数字 m(保证所有的输入都是合法的)。
输出格式
对于每一个操作,输出一行,包含操作执行后的 xmodM 的值。
题目分析
将每次操作当成一个叶子节点,用线段树来维护区间积。
先建树,先将所有的叶子节点初始化为1,在每次的操作1中,将叶子节点值改为m,并pushup一下(向上更新区间积)
在每次的操作2中,将叶子节点重新改为1,并进行pushup操作一次。
代码演示

点击查看代码
#include<iostream>
#include<vector>
#include<queue>
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 200020
#define ls u<<1
#define rs u<<1|1
int d;
struct tree
{
   int l,r;
   ll mx;


}tr[N*4];
void pushup(int u)
{
    tr[u].mx=tr[ls].mx*tr[rs].mx%d;
    return ;


}
void build(int u,int l,int r)
{
    tr[u]={l,r,1};
    if(l==r)
   {
       return ;
   }
    int mid=l+r>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
}
void change(int x,int u,int y)
{
     if(tr[u].l==x&&tr[u].r==x)
        {
            tr[u].mx=y%d;
            return ;
        }
     int m=tr[u].l+tr[u].r>>1;
     if(x<=m)
     change(x,ls,y);
     else
     change(x,rs,y);
     pushup(u);

}
int query(int u,int l,int r)
{
    if(l<=tr[u].l&&tr[u].r<=r)
        return tr[u].mx%d;
    int m=tr[u].l+tr[u].r>>1;
    int ans=1;
    if(l<=m) ans=query(ls,l,r)%d;
    if(r>m) ans=ans*query(rs,l,r)%d;
     return ans%d;
}
int main()
{
     cin.tie(NULL);
     cout.tie(nullptr);
     ios_base::sync_with_stdio(false);
     int q,m;
     int n=0;
     int c,y;
     int t;
     cin>>t;
     while(t--)
     {
     cin>>m>>d;
     build(1,1,m);
     for(int i=1;i<=m;i++)
     {
       cin>>c>>y;
       if(c==1)
       {
           change(i,1,y);
           cout<<query(1,1,m)%d<<'\n';
       }
       else {
        change(y,1,1);
        cout<<query(1,1,m)%d<<'\n';
        //cout<<t<<"\n";
       }



     }

     }
     return 0;
}
</details>
**请注意:思路来自董晓算法,哔哩哔哩搜索董晓算法。**
posted @ 2024-01-23 13:07  WandW  阅读(242)  评论(0)    收藏  举报