TJOI2018 数学计算

Description

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

Input

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

Output

对于每一个操作,输出一行,包含操作执行后的x mod M的值

Sample Input

1

10 1000000000

1 2

2 1

1 2

1 10

2 3

2 4

1 6

1 7

1 12

2 7

Sample Output

2

1

2

20

10

1

6

42

504

84

Hint

对于 20% 的数据, 1≤Q≤500
对于 100% 的数据, 1≤Q≤10^5,t≤5,M≤10^9

线段树分治裸题,我认为唯一一个坑点是我只把操作1当成了操作。。。

另外,这道题不开longlong会炸。

#include<bits/stdc++.h>
using namespace std;
#define Inc(i,L,R) for(register int i=(L);i<=(R);++i)
#define Red(j,R,L) for(register int j=(R);j>=(L);--j)
#define int long long
const int N = 1e5+10;
int n,p;
struct SegMent{
	struct Tree{
		int L,r,mul;
	}t[N<<2];
	#define Ls v<<1
	#define rs v<<1|1
	inline void build(int v,int L,int r){
		t[v]=(Tree){L,r,1};
		if(L==r)return ;
		int Mid=L+r>>1;
		build(Ls,L,Mid),build(rs,Mid+1,r);
	}
	inline void update(int v,int A,int b,int k){
		if(t[v].L>b||t[v].r<A)return ;
		if(A<=t[v].L&&t[v].r<=b)return t[v].mul=1ll*t[v].mul*k%p,void();
		update(Ls,A,b,k),update(rs,A,b,k);
	}
	inline void Query(int v,int k){
		k=1ll*k*t[v].mul%p;
		if(t[v].L==t[v].r)return cout<<k<<"\n",void();
		Query(Ls,k),Query(rs,k);
	}
}t;
struct Operator{
	int pos,m;
}a[N];
inline void init(){
	scanf("%lld%lld",&n,&p);
	t.build(1,1,n);
	Inc(i,1,n){
		int op,x;scanf("%lld%lld",&op,&x);
		if(op==1)a[i]=(Operator){i,x};
		else {
			t.update(1,a[x].pos,i-1,a[x].m);
			a[x]=(Operator){0,0};
		}
	}
	Inc(i,1,n)if(a[i].pos)t.update(1,a[i].pos,n,a[i].m);
	Inc(i,1,n)a[i]=(Operator){0,0};
}
signed main(){
	int T;scanf("%lld",&T);
	while(T--){
		init();
		t.Query(1,1);
	}
	return 0;
}

 

 

猜你喜欢

转载自blog.csdn.net/dancingz/article/details/81086617