#KD-Tree#洛谷 3710 方方方的数据结构
题目
区间加,区间乘,单点查询,撤销修改
分析
由于可以离线,不妨把下标看成第一维,时间看成第二维,那么修改操作相当于在一个矩形上加或者乘,
不妨把查询的节点看作是二维平面上的点,这样实际上就可以用 KD-Tree 来实现
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int N=150011,mod=998244353;
int ran,n,m,Q,root,ans[N];
struct rec{
int p[2];
bool operator <(const rec &t)const{
return p[ran]<t.p[ran];
}
};
struct Rec{int l,r,z,opt,ed;}q[N];
int mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
void Min(int &x,int y){x=x<y?x:y;}
void Max(int &x,int y){x=x>y?x:y;}
struct KD_Tree{
int mn[N][2],mx[N][2],son[N][2],lazy[N],w[N],tag[N]; rec p[N];
void pup(int now){
mn[now][0]=mx[now][0]=p[now].p[0];
mn[now][1]=mx[now][1]=p[now].p[1];
if (son[now][0]){
Min(mn[now][0],mn[son[now][0]][0]);
Min(mn[now][1],mn[son[now][0]][1]);
Max(mx[now][0],mx[son[now][0]][0]);
Max(mx[now][1],mx[son[now][0]][1]);
}
if (son[now][1]){
Min(mn[now][0],mn[son[now][1]][0]);
Min(mn[now][1],mn[son[now][1]][1]);
Max(mx[now][0],mx[son[now][1]][0]);
Max(mx[now][1],mx[son[now][1]][1]);
}
}
int build(int l,int r,int Ran){
if (l>r) return 0;
int mid=(l+r)>>1;
ran=Ran,nth_element(p+l,p+mid,p+1+r);
son[mid][0]=build(l,mid-1,Ran^1);
son[mid][1]=build(mid+1,r,Ran^1);
tag[mid]=1,pup(mid);
return mid;
}
void ptag(int now,int Tag,int Lazy){
w[now]=mo(1ll*w[now]*Tag%mod,Lazy);
tag[now]=1ll*tag[now]*Tag%mod;
lazy[now]=mo(1ll*lazy[now]*Tag%mod,Lazy);
}
void pdown(int now){
if (son[now][0]) ptag(son[now][0],tag[now],lazy[now]);
if (son[now][1]) ptag(son[now][1],tag[now],lazy[now]);
tag[now]=1,lazy[now]=0;
}
void update(int now,int lx,int rx,int ly,int ry,int opt,int z){
if (mx[now][0]<lx||rx<mn[now][0]||mx[now][1]<ly||ry<mn[now][1]) return;
if (lx<=mn[now][0]&&mx[now][0]<=rx&&ly<=mn[now][1]&&mx[now][1]<=ry){
if (opt==1) ptag(now,1,z);
else ptag(now,z,0);
return;
}
if (lx<=p[now].p[0]&&p[now].p[0]<=rx&&ly<=p[now].p[1]&&p[now].p[1]<=ry){
if (opt==1) w[now]=mo(w[now],z);
else w[now]=1ll*w[now]*z%mod;
}
if (tag[now]!=1||lazy[now]) pdown(now);
if (son[now][0]) update(son[now][0],lx,rx,ly,ry,opt,z);
if (son[now][1]) update(son[now][1],lx,rx,ly,ry,opt,z);
}
void query(int now){
ans[p[now].p[1]]=w[now];
if (tag[now]!=1||lazy[now]) pdown(now);
if (son[now][0]) query(son[now][0]);
if (son[now][1]) query(son[now][1]);
}
}Tre;
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
int main(){
n=iut(),Q=iut();
for (int i=1;i<=Q;++i){
int opt=iut();
if (opt<3){
int l=iut(),r=iut(),z=iut();
if (z>=mod) z-=mod;
q[i]=(Rec){l,r,z,opt,Q};
}else{
int x=iut();
if (opt==3) Tre.p[++m].p[0]=x,Tre.p[m].p[1]=i;
else q[x].ed=i-1,q[i].opt=-1;
}
}
root=Tre.build(1,m,0);
for (int i=1;i<=Q;++i) if (q[i].opt>0)
Tre.update(root,q[i].l,q[i].r,i,q[i].ed,q[i].opt,q[i].z);
Tre.query(root);
for (int i=1;i<=Q;++i) if (!q[i].opt)
print(ans[i]),putchar(10);
return 0;
}