解析
写吐了…
一开始觉得线段树分治直接做就行简直是个伞兵题,写完挂掉才想起来线段树分治会打乱操作顺序导致全假…
重构吧!
炸裂之下去贺题解,std做法
O
(
m
m
log
m
)
O(m\sqrt m\log m)
O(mmlogm) 令人谔谔,但kd-tree做法确实挺伞兵的,懊恼为啥没有想到。
写完交后发现MLE成20,用现成的datamaker跑个1000的数据发现就开了7e5个点???
…原来矩形修改开虚点复杂度会假掉啊,我直接一种植物。
重构吧!
…终于过了。
思维还是要灵活,这个转二维数点其实挺直观的。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned ll
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
inline ll read() {
ll x(0),f(1);char c=getchar();
while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
const int N=2e5+100;
const double inf=1e18;
const int mod=998244353;
inline ll ksm(ll x,ll k){
ll res=1;
while(k){
if(k&1) res=res*x%mod;
x=x*x%mod;
k>>=1;
}
return res;
}
int n,m;
struct tag{
ll mul,add;
}I=(tag){1,0};
tag operator + (const tag x,const tag y){
return (tag){x.mul*y.mul%mod,(x.add*y.mul+y.add)%mod};
}
struct pt{
int x[2];
}q[N];
int num;
int F;
bool operator < (const pt &x,const pt &y){return x.x[F]<y.x[F];}
struct tree{
int ch[2];
int l[2],r[2];
pt o;
tag ans,laz;
}tr[N];
inline void pushup(int k){
tr[k].l[0]=tr[k].r[0]=tr[k].o.x[0];
tr[k].l[1]=tr[k].r[1]=tr[k].o.x[1];
for(int o=0;o<=1;o++){
int son=tr[k].ch[o];
if(!son) continue;
for(int d=0;d<=1;d++){
tr[k].l[d]=min(tr[k].l[d],tr[son].l[d]);
tr[k].r[d]=max(tr[k].r[d],tr[son].r[d]);
}
}
return;
}
inline void Add(int k,const tag &o){
if(!k) return;
tr[k].ans=tr[k].ans+o;
tr[k].laz=tr[k].laz+o;
}
inline void pushdown(int k){
Add(tr[k].ch[0],tr[k].laz);
Add(tr[k].ch[1],tr[k].laz);
tr[k].laz=I;
}
int tot;
int build(int l,int r,int d){
if(l>r) return 0;
int now=++tot,mid=(l+r)>>1;
F=d;
nth_element(q+l,q+mid,q+r+1);
tr[now].o=q[mid];
tr[now].ans=tr[now].laz=I;
tr[now].ch[0]=build(l,mid-1,d^1);
tr[now].ch[1]=build(mid+1,r,d^1);
pushup(now);
return now;
}
struct node{
int l[2],r[2];
};
void upd(int k,const node &o,const tag &w){
if(!k) return;
if(o.l[0]>tr[k].r[0]||o.r[0]<tr[k].l[0]||o.l[1]>tr[k].r[1]||o.r[1]<tr[k].l[1]) return;
if(o.l[0]<=tr[k].l[0]&&tr[k].r[0]<=o.r[0]&&o.l[1]<=tr[k].l[1]&&tr[k].r[1]<=o.r[1]){
Add(k,w);
return;
}
pushdown(k);
if(o.l[0]<=tr[k].o.x[0]&&tr[k].o.x[0]<=o.r[0]&&o.l[1]<=tr[k].o.x[1]&&tr[k].o.x[1]<=o.r[1])
tr[k].ans=tr[k].ans+w;
upd(tr[k].ch[0],o,w);
upd(tr[k].ch[1],o,w);
}
ll ans[N];
void getans(int k){
if(!k) return;
ans[tr[k].o.x[1]]=tr[k].ans.add;
pushdown(k);
getans(tr[k].ch[0]);
getans(tr[k].ch[1]);
return;
}
int op[N],l[N],r[N],val[N],pos[N],tim[N];
signed main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
n=read();m=read();
for(int i=1;i<=m;i++){
op[i]=read();
if(op[i]<=2){
l[i]=read();r[i]=read();
val[i]=read();
tim[i]=m;
}
else if(op[i]==3){
pos[i]=read();
q[++num]=(pt){pos[i],i};
}
else tim[read()]=i;
}
int rt=build(1,num,0);
for(int i=1;i<=m;i++){
if(op[i]<=2){
tag w=I;
if(op[i]==1) w.add=val[i];
else w.mul=val[i];
node o;
o.l[0]=l[i];o.r[0]=r[i];
o.l[1]=i;o.r[1]=tim[i];
//printf("upd: (%d %d) (%d %d) mul=%d add=%d\n",o.l[0],o.r[0],o.l[1],o.r[1],mul,add);
upd(rt,o,w);
}
}
getans(rt);
for(int i=1;i<=m;i++){
if(op[i]==3) printf("%lld\n",ans[i]);
}
debug("tot=%d\n",tot);
return 0;
}
/*
*/