题目大意:
维护一个算式,,每次询问一个x带入算式的值是多少,从左到右计算,计算有三种:’+’,’*’,’^’,例子如下:
算式为 +2 *3 ^2 +4
X=3时,Ans=((3+2)*3)^2+4=229.
X=2时,Ans=((2+2)*3)^2+4=148.
支持这两种操作:
1:询问x带入算式的值。
2:将第k个地方的计算符号改变。
(n<=50000,m<=50000,输入的所有数小于29393,n为计算符号数,m为操作数)。
答案Mod 29393 输出。
题解:毕姥爷又玩模数….
29393=7*13*17*19….在学了中国剩余定理之前根本不知道这代表什么2333.
然后就比较简单了,我们维护4棵线段树,每一个分别代表Mod(7,13,17,19)的答案。
因为模数很小,所以说我们线段树直接暴力即可,val[x][i][j]表示在第j个模数的模意义下的线段树上,输入i,经过当前节点x及其子树的所有运算之后,输出的值,这个暴力维护即可,每棵每次操作复杂度为Mod*log。
然后如果查询x,我们分别在四棵线段树的顶点1查询输入x之后得到的值,一共4个,然后中国剩余定理合并这四个解就可以了。
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <ctime>
using namespace std;
int M[5],t[5],flag[100010],A[100010],Point[5];
int n,m,a,pos,Ans;
int getint() {
char c = 'd';
int ret = 0;
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') ret = ret * 10 + c - '0',c = getchar();
return ret;
}
int ksm(int x,int y,int Mod) {
int ret = 1;
x %= Mod;
for(int i = y;i > 0;i >>= 1) {
ret *= (i % 2 == 1) ? x:1;
ret %= Mod;
x = (x * x) % Mod;
}
return ret;
}
void prework() {
M[1] = 13 * 17 * 19;
M[2] = 7 * 17 * 19;
M[3] = 7 * 13 * 19;
M[4] = 7 * 13 * 17;
t[1] = ksm(M[1],5,7);
t[2] = ksm(M[2],11,13);
t[3] = ksm(M[3],15,17);
t[4] = ksm(M[4],17,19);
}
struct Segment_Tree {
int Prime[5],val[400010][5][20];
Segment_Tree () {
Prime[1] = 7;
Prime[2] = 13;
Prime[3] = 17;
Prime[4] = 19;
}
void build(int Now,int l,int r,int k) {
if(l == r) {
if(flag[r] == 1) {
for(int i = 0;i <= Prime[k] - 1;i ++) {
val[Now][k][i] = (i + A[r]) % Prime[k];
}
}
if(flag[r] == 2) {
for(int i = 0;i <= Prime[k] - 1;i ++) {
val[Now][k][i] = (i * A[r]) % Prime[k];
}
}
if(flag[r] == 3) {
for(int i = 0;i <= Prime[k] - 1;i ++) {
val[Now][k][i] = ksm(i,A[r],Prime[k]) % Prime[k];
}
}
return ;
}
int Mid = (l + r) >> 1;
build(Now << 1,l,Mid,k);
build(Now << 1 | 1,Mid+1,r,k);
for(int i = 0;i <= Prime[k] - 1;i ++) {
int p = val[Now << 1][k][i];
val[Now][k][i] = val[Now << 1 | 1][k][p];
}
return ;
}
void insert(int Now,int l,int r,int k,int x) {
if(l == r) {
if(flag[r] == 1) {
for(int i = 0;i <= Prime[k] - 1;i ++) {
val[Now][k][i] = (i + A[r]) % Prime[k];
}
}
if(flag[r] == 2) {
for(int i = 0;i <= Prime[k] - 1;i ++) {
val[Now][k][i] = (i * A[r]) % Prime[k];
}
}
if(flag[r] == 3) {
for(int i = 0;i <= Prime[k] - 1;i ++) {
val[Now][k][i] = ksm(i,A[r],Prime[k]) % Prime[k];
}
}
return ;
}
int Mid = (l + r) >> 1;
if(x <= Mid) insert(Now << 1,l,Mid,k,x);
if(x > Mid) insert(Now << 1 | 1,Mid+1,r,k,x);
for(int i = 0;i <= Prime[k] - 1;i ++) {
int p = val[Now << 1][k][i];
val[Now][k][i] = val[Now << 1 | 1][k][p];
}
return ;
}
int Ask(int Now,int l,int r,int k,int x) {
int ret = val[Now][k][x];
return ret;
}
};Segment_Tree T;
int Merge() {
int ret = 0;
for(int i = 1;i <= 4;i ++) {
ret += Point[i] * M[i] * t[i];
ret %= (7 * 13 * 17 * 19);
}
return ret;
}
int main() {
//freopen("calculator.in","r",stdin);
//freopen("calculator.out","w",stdout);
prework();
n = getint();
m = getint();
for(int i = 1;i <= n;i ++) {
char c = 'd';
while(c != '*' && c != '^' && c != '+') c = getchar();
a = getint();
if(c == '+') flag[i] = 1,A[i] = a;
else if(c == '*') flag[i] = 2,A[i] = a;
else if(c == '^') flag[i] = 3,A[i] = a;
}
T.build(1,1,n,1);
T.build(1,1,n,2);
T.build(1,1,n,3);
T.build(1,1,n,4);
for(int i = 1;i <= m;i ++) {
int mp = 0;
mp = getint();
if(mp == 1) {
a = getint();
Point[1] = T.Ask(1,1,n,1,a % 7);
Point[2] = T.Ask(1,1,n,2,a % 13);
Point[3] = T.Ask(1,1,n,3,a % 17);
Point[4] = T.Ask(1,1,n,4,a % 19);
Ans = Merge();
printf("%d\n", Ans );
}
if(mp == 2) {
pos = getint();
char c = 'd';
while(c != '*' && c != '^' && c != '+') c = getchar();
a = getint();
if(pos == 0) pos = 1;
if(c == '+') flag[pos] = 1,A[pos] = a;
else if(c == '*') flag[pos] = 2,A[pos] = a;
else if(c == '^') flag[pos] = 3,A[pos] = a;
T.insert(1,1,n,1,pos);
T.insert(1,1,n,2,pos);
T.insert(1,1,n,3,pos);
T.insert(1,1,n,4,pos);
}
}
return 0;
}