你有一个数 ,初始为 。你有两种操作,分别为:
-
- 给定一个数 ,把 变成 ,然后输出 对 取模的值。
-
- 给定一个数 ,把 变为 第 次操作所乘的数。如第 次操作所乘数为 ,则把 变为 。数据保证第 次操作一定是操作 ,且每个操作最多被除一次,即保证 在任何时候都是一个整数。操作后,输出 对 取模的值。
直接模拟会因为爆 long long
的问题导致代码非常复杂,甚至无法编写。
考虑强大的数据结构——线段树。建立一棵线段树,其叶子节点都是对于的乘数,每个非叶子节点的值为其左右儿子的值的乘积对 取模的值。这样,任意时候都有 该线段树的根的值。
操作 可以直接上,操作 可以看做是把第 次的乘数改为 。因此,我们只需要打一个线段树修改即可。
const int N=1e5+100;
#define ll long long
ll mod;int tot,G[N];
int test_number,q;
struct Segment_tree{
ll sum[N<<2];//记得4倍空间
inline void pushup(int o){
sum[o]=sum[o<<1]*sum[o<<1|1]%mod;
}
inline void build(int o,int l,int r){
if (l==r){sum[o]=1ll;return;}
register int mid=(l+r)>>1;
build(o<<1|1,mid+1,r);
build(o<<1,l,mid);
pushup(o);return;
}
void updata(int o,int l,int r,int p,ll v){
if (l==r){sum[o]=v;return;}
register int mid=(l+r)>>1;
if (p<=mid) updata(o<<1,l,mid,p,v);
else updata(o<<1|1,mid+1,r,p,v);
pushup(o);return;
}
}SGT;
#define gc getchar()
#define g(c) isdigit(c)
inline ll read(){
char c=0;ll x=0;bool f=0;
while (!g(c)) f=c=='-',c=gc;
while (g(c)) x=x*10+c-48,c=gc;
return f?-x:x;
}
namespace fast_write{
void write(ll a,bool b){
if (a==0){
if (b) putchar('0');
}
else{
write(a/10,false);
putchar(a%10+'0');
}
}
void print(ll a,char c){
write(a,true);
putchar(c);
}
}
int main(){
test_number=read();
while (test_number--){
q=read();mod=read();
SGT.build(1,1,q);tot=0;
memset(G,0,sizeof(G));
for(int i=1;i<=q;i++){
int opt=read();ll t=read();
if (opt==2) SGT.updata(1,1,q,G[t],1);
else SGT.updata(1,1,q,G[i]=(++tot),t%mod);
fast_write::print(SGT.sum[1]%mod,'\n');
}
}
return 0;
}
https://www.luogu.com.cn/problem/P1575
很简单,直接用一个栈模拟即可。如果 not
后面不是 true
或 false
的话,就输出 error
。
#include <bits/stdc++.h>
using namespace std;
stack<bool> num;
stack<string> oper;
int cti(string s){
if (s=="or") return 1;
if (s=="and") return 2;
if (s=="not") return 3;
return 0;
}
inline bool calc(){
register bool x,y;
if (num.size()){
y=num.top();num.pop();
}
else return false;
if (num.size()){
x=num.top();num.pop();
}
else return false;
string c=oper.top();oper.pop();
if (c=="and") num.push(x&&y);
else num.push(x||y);
return true;
}
bool Not(string s){
if (s=="true") return 0;
if (s=="false") return 1;
}
string s;bool flag;
int main(){
getline(cin,s);
stringstream ss(s);
while (ss>>s){
if (s=="not"){
if (ss>>s){
if (s!="true"&&s!="false"){
printf("error");
return 0;
}
else num.push(Not(s));
}
else{
printf("error");
return 0;
}
flag=false;
}
else if (cti(s)){
if (num.empty()){
printf("error");
return 0;
}
while (oper.size()&&cti(oper.top())>=cti(s)){
if (!calc()){
printf("error");
return 0;
}
}
oper.push(s);
flag=false;
}
else{
if (flag){
printf("error");
return 0;
}
num.push(!Not(s));
flag=true;
}
}
while (oper.size()){
if (!calc()){
printf("error");
return 0;
}
}
if (num.size()!=1){
printf("error");
return 0;
}
if (num.top()) printf("true");
else printf("false");
return 0;
}
可是,这样真的就 AC
了吗?不是,有 个点错了。为什么?
因为数据中有如这样的情况 not not true
,这种情况下我们的程序会输出 error
,但是它实际上是应该输出 true
的。我们特殊处理即可。
#include <bits/stdc++.h>
using namespace std;
stack<bool> num;
stack<string> oper;
int cti(string s){
if (s=="or") return 1;
if (s=="and") return 2;
if (s=="not") return 3;
return 0;
}
inline bool calc(){
register bool x,y;
if (num.size()){
y=num.top();num.pop();
}
else return false;
if (num.size()){
x=num.top();num.pop();
}
else return false;
string c=oper.top();oper.pop();
if (c=="and") num.push(x&&y);
else num.push(x||y);
return true;
}
inline bool Not(string s){
if (s=="true") return 0;
else return 1;
}
string s;bool flag,sign;
int main(){
getline(cin,s);
stringstream ss(s);
while (ss>>s){
if (s=="not"){
if (ss>>s){
if (s!="true"&&s!="false"&&s!="not"){
printf("error");
return 0;
}
if (s=="true"||s=="false")
num.push(Not(s));
else{
sign=false;
while (ss>>s){
if (s!="true"&&s!="false"&&s!="not"){
printf("error");
return 0;
}
else{
if (s=="not") sign=!sign;
else{
num.push(sign?Not(s):!Not(s));
break;
}
}
}
}
}
else{
printf("error");
return 0;
}
flag=false;
}
else if (cti(s)){
if (num.empty()){
printf("error");
return 0;
}
while (oper.size()&&cti(oper.top())>=cti(s)){
if (!calc()){
printf("error");
return 0;
}
}
oper.push(s);
flag=false;
}
else{
if (flag){
printf("error");
return 0;
}
num.push(!Not(s));
flag=true;
}
}
while (oper.size()){
if (!calc()){
printf("error");
return 0;
}
}
if (num.size()!=1){
printf("error");
return 0;
}
if (num.top()) printf("true");
else printf("false");
return 0;
}
/*
注意!需要特殊判断如not not true这样的情况,
否则无法通过第七个测试点
*/
这提示我们,只有全面的思考,才能获得高分或者 AC
!