• BZOJ4066


    原题链接

    Description

    对于一个n×n(n5×105)的矩阵进行m(m2×105)次操作:
    1. 将格子(x,y)里的数字加上A(A>0)
    2. 求矩形(x1,y1)(x2,y2)中的数字和。
    强制在线,空间限制20MB。

    Solution

    k-d树。
    对于操作1,将(x,y)插入树中,当树的大小达到一定程度就重建整棵树。
    对于操作2,做法类似于线段树,如果查询矩形完全包含目前子树所表示的矩形,就返回这个子树内的和;否则就递归的向左右子树内查询。

    并不知道k-d树的时间复杂度如何算。

    Code

    这个代码目前TLE!明天问问Icefox大佬
    噫!我过了

    //简单题
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    int pre;
    inline char gc()
    {
        static char now[1<<16],*S,*T;
        if(S==T) {T=(S=now)+fread(now,1,1<<16,stdin); if(S==T) return EOF;}
        return *S++;
    }
    inline int read()
    {
        int x=0; char ch=gc();
        while(ch<'0'||'9'<ch) ch=gc();
        while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
        return x^pre;
    }
    int const N=2e5+10;
    int const INF=0x7FFFFFFF;
    int n;
    #define chL ch[p][0]
    #define chR ch[p][1]
    int D,ndCnt,rt,ch[N][2],sum[N];
    struct point
    {
        int c[2],v;
        point(int x=0,int y=0,int v0=0){c[0]=x,c[1]=y,v=v0;}
    }pt[N];
    struct zone
    {
        int c1[2],c2[2];
        zone(int x1=0,int y1=0,int x2=0,int y2=0)
        {
            c1[0]=x1,c1[1]=y1;
            c2[0]=x2,c2[1]=y2;
        }
    }zn[N];
    bool cmpPt(point x,point y) {return x.c[D]<y.c[D];}
    void create(int p,point A)
    {
        pt[p]=A;
        for(int k=0;k<2;k++) zn[p].c1[k]=zn[p].c2[k]=A.c[k];
        chL=chR=0; sum[p]=A.v;
    }
    void update(int p)
    {
        for(int k=0;k<2;k++)
        {
            zn[p].c1[k]=min(pt[p].c[k],min(zn[chL].c1[k],zn[chR].c1[k]));
            zn[p].c2[k]=max(pt[p].c[k],max(zn[chL].c2[k],zn[chR].c2[k]));
        }
        sum[p]=pt[p].v+sum[chL]+sum[chR];
    }
    inline bool equal(point x,point y)
    {
        for(int k=0;k<2;k++) if(x.c[k]!=y.c[k]) return false;
        return true;
    }
    void build(int &p,int L,int R,int k0)
    {
        int mid=L+R>>1; D=k0;
        nth_element(pt+L,pt+mid,pt+R+1,cmpPt);
        create(p=mid,pt[mid]);
        if(L<mid) build(chL,L,mid-1,k0^1);
        if(mid<R) build(chR,mid+1,R,k0^1);
        update(p);
    }
    void ins(int &p,point A,int k0)
    {
        if(p==0) {create(p=++ndCnt,A); return;}
        if(equal(A,pt[p])) {pt[p].v+=A.v,sum[p]+=A.v; return;}
        ins(ch[p][A.c[k0]>pt[p].c[k0]],A,k0^1);
        update(p);
    }
    inline bool in(zone z,zone z0)
    {
        for(int k=0;k<2;k++) if(z0.c1[k]<z.c1[k]||z.c2[k]<z0.c2[k]) return false;
        return true;
    }
    inline bool in(zone z,point A)
    {
        for(int k=0;k<2;k++) if(A.c[k]<z.c1[k]||z.c2[k]<A.c[k]) return false;
        return true;
    }
    inline bool out(zone z,zone z0)
    {
        for(int k=0;k<2;k++)
        {
            bool outL=z0.c1[k]<z.c1[k]&&z0.c2[k]<z.c1[k];
            bool outR=z0.c1[k]>z.c2[k]&&z0.c2[k]>z.c2[k];
            if(outL||outR) return true;
        }
        return false;
    }
    int query(int p,zone z)
    {
        if(in(z,zn[p])) return sum[p];
        int res=0;
        if(in(z,pt[p])) res+=pt[p].v;
        if(!out(z,zn[chL])) res+=query(chL,z);
        if(!out(z,zn[chR])) res+=query(chR,z);
        return res;
    }
    int main()
    {
        pre=0; n=read();
        for(int k=0;k<2;k++) zn[0].c1[k]=INF,zn[0].c2[k]=-INF;
        while(true)
        {
            int opt=read()^pre;
            if(opt==1)
            {
                int x=read(),y=read(),k=read();
                ins(rt,point(x,y,k),0);
                if(ndCnt%10000==0) rt=0,build(rt,1,ndCnt,0);
            }
            else if(opt==2)
            {
                int x1=read(),y1=read(),x2=read(),y2=read();
                printf("%d
    ",pre=query(rt,zone(x1,y1,x2,y2)));
            }
            else break;
        }
        return 0;
    }

    P.S.

    到底什么锅啊!跟Icefox的代码对拍十组都一样啊!
    建树/插入节点的时候,参数要单独传一个k0,表示当前这层以第k0维作为划分标准,而不能用全局变量。那个全局变量D只是用于做nth_element()的…
    对拍正确可能是因为只有两维+数据分散,有时候k0错了也能跳到正确的子树上

  • 相关阅读:
    browser-sync events.js:85 throw er; // Unhandled 'error' event
    js判断页面放大缩小
    uniapp小实例-新闻列表及详情
    uniapp 分享接口
    uniapp--第三方登录 小程序登录
    vue h5转换uni-app指南(vue转uni、h5转uni)
    uniapp详解及配置
    uniapp快速上手
    Vuex 的项目实例11 列表数据的按需切换
    Vuex 的项目实例10 底部按钮高亮切换
  • 原文地址:https://www.cnblogs.com/VisJiao/p/8485747.html
Copyright © 2020-2023  润新知