Luogu P4588 数学运算 题解 [ 绿 ] [ 线段树 ]
虽然是一个很典的题,但里面的思想还是比较值得记录的。
假做法
一开始看到此题还以为是乘法逆元的模板题,但看到
因此,本题不能进行任何与原来的值有关的(要做逆运算的)修改,所以树状数组之类的解法直接被毙掉了。
正解
本题的 trick:对于在正操作之后要撤销正操作(即执行反操作),且反操作较难实现的,可以选择从第一个正操作起,把所有没有被撤销的正操作算一遍,就是答案。
因此,直接用线段树维护一下区间乘法就 AC 了。
注意多测不清空,保龄两行泪。
线段树的清空,一般只要重新 build
一遍就可以了。
代码
#include <bits/stdc++.h>
#define fi first
#define se second
#define lc (p<<1)
#define rc ((p<<1)|1)
using namespace std;
typedef long long ll;
typedef pair<int,int> pi;
const int N=100005;
ll t,q,mod,m,op,a[100005],pos[100005];
struct node{
int l,r;
ll mul;
}tr[4*N];
void pushup(int p)
{
tr[p].mul=(tr[lc].mul*tr[rc].mul)%mod;
}
void build(int p,int ln,int rn)
{
tr[p]={ln,rn,a[ln]};
if(ln==rn)return;
int mid=(tr[p].l+tr[p].r)>>1;
build(lc,ln,mid);
build(rc,mid+1,rn);
pushup(p);
}
void update(int p,int x,ll v)
{
if(tr[p].l==x&&tr[p].r==x)
{
tr[p].mul=v%mod;
return;
}
int mid=(tr[p].l+tr[p].r)>>1;
if(x<=mid)update(lc,x,v);
else update(rc,x,v);
pushup(p);
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--)
{
cin>>q>>mod;
for(int i=1;i<=q;i++)a[i]=1;
build(1,1,q);
int n=0;
for(int i=1;i<=q;i++)
{
cin>>op>>m;
if(op==1)
{
m%=mod;
update(1,++n,m);
cout<<tr[1].mul%mod<<endl;
}
else
{
update(1,pos[m],1);
cout<<tr[1].mul%mod<<endl;
}
pos[i]=n;
}
}
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战