【TJOI2018】数学计算的解析——针对询问建立的线段树

题目:luogu4588.

题目大意:

对于一个数x,需要支持两种操作:

1.格式1 m,使得x=x*m,并输出x%mod的值.

2.格式2 pos,使得x=x/第pos操作的m,并输出x%mod的值.

不得不说这道题的思路确实比较好,但是想到也不是太难.

一开始我看到要对一个数取模还有除法,我第一个想到的方法就是直接特别暴力地使用逆元,然后直接做.

可是这道题由于模数不保证是质数,这代表我们不能O(log(n))处理逆元,然而我们要使用O(sqrt(n))的欧拉定理求逆元会TLE,所以我们这道题其实并不能以一种数学角度去做.

现在我们重新换一种方式做,现在我们维护一个序列便是每次操作1后会对乘积产生的贡献,特别的,对于操作2,我们只记录一个数值1.

现在,对于每一次操作2,我们都将位置pos的数值修改成1,并输出一个前缀积.

这样这道题就完美解决了.

代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000;
const int INF=(1<<30)-1+(1<<30);
struct tree{
  int l,r;
  LL mul;
}tr[N*5];
int q;
LL mod;
void build(int L,int R,int k=1){
  tr[k].l=L;tr[k].r=R;
  if (L==R) return;
  int mid=L+R>>1;
  build(L,mid,k<<1),build(mid+1,R,k<<1|1);
}
void change(int x,LL num,int k=1){
  if (tr[k].l==tr[k].r){
    tr[k].mul=num%mod;
    return;
  }
  int mid=tr[k].l+tr[k].r>>1;
  if (x<=mid) change(x,num,k<<1);
  else change(x,num,k<<1|1);
  tr[k].mul=tr[k<<1].mul*tr[k<<1|1].mul%mod;
}
LL query(int L,int R,int k=1){
  if (L==tr[k].l&&R==tr[k].r) return tr[k].mul;
  int mid=tr[k].l+tr[k].r>>1;
  if (R<=mid) return query(L,R,k<<1);
  else if (L>mid) return query(L,R,k<<1|1);
    else return query(L,mid,k<<1)*query(mid+1,R,k<<1|1)%mod;
}
Abigail into(){
  for (int i=0;i<N*5;i++)
    tr[i].l=tr[i].r=0,tr[i].mul=1;
  scanf("%d%lld",&q,&mod);
}
Abigail work(){
  int opt,pos;
  LL m;
  build(1,q);
  for (int i=1;i<=q;i++){
    scanf("%d",&opt);
    if (opt==1){
      scanf("%lld",&m);
      change(i,m);
      printf("%lld\n",query(1,i));
    }else{
      scanf("%d",&pos);
      change(pos,1);change(i,1);
      printf("%lld\n",query(1,i));
    }
  }
}
Abigail outo(){
}
int main(){
  int T;
  scanf("%d",&T);
  while (T--){
    into();
    work();
    outo();
  }
  return 0;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/81138021