【题解】Luogu P4588 [TJOI2018]数学计算

原题传送门

这题是线段树的模板题

显而易见,直接模拟是不好模拟的(取模后就不好再除了)

我们按照时间来建一颗线段树

线段树初始值都为1,用来维护乘积

第一种操作就在当前时间所对应的节点上把乘数改成m

第二种操作就是把第pos个节点的乘数该回1

每次询问的答案就是线段树根节点维护的数值(pushup时要取模)

#include <bits/stdc++.h>
#define N 100005
#define ll long long
#define getchar nc
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf; 
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; 
}
inline ll read()
{
    register ll x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void write(register int x)
{
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[20];register int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
int n;
ll mod;
struct SegmentTree{
    ll mul[N<<3];
    inline void init(register int x,register int l,register int r)
    {
        mul[x]=1;
        if(l==r)
            return;
        int mid=l+r>>1;
        init(x<<1,l,mid);
        init(x<<1|1,mid+1,r);
    }
    inline void pushup(register int x)
    {
        mul[x]=mul[x<<1]*mul[x<<1|1]%mod;
    }
    inline void update(register int x,register int l,register int r,register int pos,register int v)
    {
        if(l==r)
        {
            mul[x]=v;
            return;
        }
        int mid=l+r>>1;
        if(pos<=mid)
            update(x<<1,l,mid,pos,v);
        else 
            update(x<<1|1,mid+1,r,pos,v);
        pushup(x);
    }
}tr;
int main()
{
    int T=read();
    while(T--)
    {
        n=read(),mod=read();
        tr.init(1,1,n);
        for(register int i=1;i<=n;++i)
        {
            int opt=read();
            ll x=read();
            if(opt==1)
                tr.update(1,1,n,i,x);
            else
                tr.update(1,1,n,x,1);
            write(tr.mul[1]),puts("");
        }
    }
    return 0;
 } 
posted @ 2019-01-29 17:44  JSOI爆零珂学家yzhang  阅读(256)  评论(0编辑  收藏  举报