bzoj 5334: [Tjoi2018]数学计算 线段树

题意

小豆现在有一个数x,初始值为1. 小豆有Q次操作,操作有两种类型:
1 m: x = x * m ,输出 x%mod;
2 pos: x = x / 第pos次操作所乘的数(保证第pos次操作一定为类型1,对于每一个类型1 的操作至多会被除一次),输出x%mod

一共有t组输入(t ≤ 5)
对于每一组输入,第一行是两个数字Q, mod(Q ≤ 100000, mod ≤ 1000000000);
接下来Q行,每一行为操作类型op,操作编号或所乘的数字m(保证所有的输入都是合法的).
1 ≤ Q ≤ 100000

分析

看到路标你是不是会做了啊
一开始往数学方向想,就想不出来,可能出现不互质的情况
考虑我们可修改,就是线段树咯,对每个操作建一个以第几个操作为下标的线段树,存上值就好了

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 100010;
inline ll read()
{
  ll p=0; ll f=1; char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}
ll q,mod; ll rt,lc[N<<2],rc[N<<2],c[N<<2],tot;
void link(ll &u,ll L,ll R,ll k,ll cc)
{
  if(!u) u = ++tot;
  if(L==R){c[u] = cc; return ;}
  ll mid = (L+R)>>1;
  if(k<=mid) link(lc[u],L,mid,k,cc);
  else link(rc[u],mid+1,R,k,cc);
  c[u] = c[lc[u]] * c[rc[u]] % mod;
}
int id[N];
int main()
{
  ll t = read();
  while(t--)
  {
    q = read(); mod = read();
    memset(lc,0,sizeof(lc));
    memset(rc,0,sizeof(rc));
    memset(id,0,sizeof(id));
    rt = tot = 0;
    for(ll i=1;i<=q;i++) link(rt,1,q,i,1); ll pos = 0;
    for(ll T=1;T<=q;T++)
    {
      ll op = read(); ll x = read();
      if(op==1){pos ++; id[T] = pos; link(rt,1,q,pos,x);}
      else link(rt,1,q,id[x],1);
      printf("%lld\n",c[1]);
    }
  }
  return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_39708759/article/details/80381197