解析
写吐了…
一开始觉得线段树分治直接做就行简直是个伞兵题,写完挂掉才想起来线段树分治会打乱操作顺序导致全假…
重构吧!
炸裂之下去贺题解,std做法 O(mmlogm)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_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifn=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;
}
/**/