題目大意:
維護一個算式,,每次詢問一個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;
}