#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;
}
posted @ 2024-03-02 02:06  lemondinosaur  阅读(4)  评论(0编辑  收藏  举报