关于线段树与四分树的卡常
  • 板块学术版
  • 楼主reveal
  • 当前回复11
  • 已保存回复11
  • 发布时间2022/3/16 21:13
  • 上次更新2023/10/28 06:25:55
查看原帖
关于线段树与四分树的卡常
523491
reveal楼主2022/3/16 21:13

无需看的前情

好吧是这样的有人把 Ynoi rprmq2 搬到了校内赛上,目前全机房最快的代码,在那题(数据为五万)需要 4.3s。

时限因为校内老爷机可视作为 2s,据推算标程本地用时大约为 0.8s~1s.

求教万能的谷民一些数据结构卡常技巧。

看不懂也随便提点建议也好哇。

#include<set>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define uni unsigned
#define ll long long
#define getrk(x,y,z) lower_bound(y,y+z,x)-y
using namespace std;
const int N=50010,B0=800,FSIZE=1<<23;
uni m,dx[N],dy[N],lex,ley;
ll b[B0][B0],mx[B0][B0];
char BuF[FSIZE],*InF=BuF,WuF[FSIZE],*OnF=WuF,st[11],*c=st;
template<typename T>void read(T &x){
    for(;48>*InF||*InF>57;++InF);
    for(x=0;47<*InF&&*InF<58;x=x*10+(*InF++^48));
}
void write(ll x){
    if(!x) *OnF++=48;
    for(;x;*++c=x%10^48,x/=10);
    for(;c!=st;*OnF++=*c--);
    *OnF++='\n';
}
void cmax(ll &x,ll y){if(x<y) x=y;}
struct ques{
    uni x,y;
    int z00,z01,z10,z11;
    bool operator<(ques b)const{return(x<b.x);}
    void get(){
        read(x);read(y);read(z00);read(z01);read(z10);read(z11);
    }
}q[N];
struct ST{    // 线段树,支持区间加,区间历史最值,历史最值回滚
    struct node{
        uni mid;
        ll add,mx,_add,_mx;
        bool ret;
    }a[N<<7];
    void _add(node &x,ll y,ll z){
        cmax(x._add,x.add+z);
        cmax(x._mx,x.mx+z);
        x.add+=y;
        x.mx+=y;
    }
    void reset(uni x=1){
        node &w=a[x];
        _add(a[x<<1],w.add,w._add);
        _add(a[x<<1|1],w.add,w._add);
        w.add=w._add=0;
        w._mx=w.mx;
        w.ret=1;
    }
    void pushdown(uni x){
        node &w=a[x];
        if(w.ret){
            reset(x<<1);
            reset(x<<1|1);
            w.ret=0;
        }
        if(w.add||w._add){
            _add(a[x<<1],w.add,w._add);
            _add(a[x<<1|1],w.add,w._add);
            w.add=w._add=0;
        }
    }
    void build(uni bl,uni br,uni p=1,uni l=1,uni r=m){
        a[p]=node();
        if(l==r) return;
        if(bl==br){
            a[p].mid=(l+r)>>1;
            build(bl,br,p<<1,l,a[p].mid);
            return(build(bl,br,p<<1|1,a[p].mid+1,r));
        }
        uni bd=(bl+br)>>1; 
        a[p].mid=dy[bd+1]-1;
        build(bl,bd,p<<1,l,a[p].mid);
        build(bd+1,br,p<<1|1,a[p].mid+1,r);
    }
    void push(uni bl,uni br,ll *s,uni p=1){
        if(bl==br){
            s[bl]=a[p]._mx;
            return;
        }
        pushdown(p);
        push(bl,(bl+br)>>1,s,p<<1);
        push(((bl+br)>>1)+1,br,s,p<<1|1);
    }
    void modify(uni x,int y,int z,uni p=1,uni l=1,uni r=m){
        pushdown(p);
        if(x<=a[p].mid) modify(x,y,z,p<<1,l,a[p].mid);
        else _add(a[p<<1],y,y);
        if(x>a[p].mid+1) modify(x,y,z,p<<1|1,a[p].mid+1,r);
        else _add(a[p<<1|1],z,z);
        a[p].mx=max(a[p<<1].mx,a[p<<1|1].mx);
        a[p]._mx=max(a[p<<1]._mx,a[p<<1|1]._mx);
    }
}t;
struct ST2{    // 四分树,支持子矩阵加,子矩阵最大值
    struct node{
        ll mx,add;
        uni s0,s1,s2,s3;
    }a[N<<5];
    ll ans0,ans1,ans2,ans3;
    uni size,x,y;
    int z0,z1,z2,z3;
    void build(uni p=1,uni l0=0,uni r0=lex,uni l1=0,uni r1=ley){
        a[p]=node();
        if(l0==r0&&l1==r1){
            a[p].mx=b[l0][l1];
            return;
        }
        uni mdx=(l0+r0)>>1,mdy=(l1+r1)>>1;
        build(a[p].s0=++size,l0,mdx,l1,mdy);
        if(l1!=r1) build(a[p].s1=++size,l0,mdx,mdy+1,r1);
        if(l0!=r0){
            build(a[p].s2=++size,mdx+1,r0,l1,mdy);
            if(l1!=r1) build(a[p].s3=++size,mdx+1,r0,mdy+1,r1);
        }
        a[p].mx=max(max(a[a[p].s0].mx,a[a[p].s1].mx),max(a[a[p].s2].mx,a[a[p].s3].mx));
    }
    void _add(node &x,int z){
        x.mx+=z;
        x.add+=z;
    }
    void get(uni p=1,uni l0=0,uni r0=lex,uni l1=0,uni r1=ley,ll up=0){
        node &w=a[p];
        if(r0<x&&r1<y){
            cmax(ans0,w.mx+up);
            return(_add(w,z0));
        }
        if(r0<x&&y<=l1){
            cmax(ans1,w.mx+up);
            return(_add(w,z1));
        }
        if(x<=l0&&r1<y){
            cmax(ans2,w.mx+up);
            return(_add(w,z2));
        }
        if(x<=l0&&y<=l1){
            cmax(ans3,w.mx+up);
            return(_add(w,z3));
        }
        uni mdx=(l0+r0)>>1,mdy=(l1+r1)>>1;
        get(w.s0,l0,mdx,l1,mdy,up+=w.add);
        if(w.s1) get(w.s1,l0,mdx,mdy+1,r1,up);
        if(w.s2) get(w.s2,mdx+1,r0,l1,mdy,up);
        if(w.s3) get(w.s3,mdx+1,r0,mdy+1,r1,up);
        w.mx=max(max(a[w.s0].mx,a[w.s1].mx),max(a[w.s2].mx,a[w.s3].mx))+w.add;
    }
}bt;
#define lsh(a,b)\
    sort(a,a+end-i+1);\
    b=unique(a,a+end-i+1)-a;\
    a[b--]=m+1;
multiset<ques> qs;
void before(uni i,uni end){    // 块间贡献
    t.build(0,ley);
    memset(b,0,sizeof(b));
    for(auto &j:qs) t.modify(j.y,j.z00,j.z01);
    uni col=0;
    for(auto j=qs.begin(),k=j;j!=qs.end();){
        for(;j->x>dx[col+1];t.reset()) t.push(0,ley,b[col++]);
        for(;k!=qs.end()&&j->x==k->x;++k) t.modify(k->y,-k->z00,-k->z01);
        for(;j->x>=dx[col+1]&&col<=lex;t.reset()) t.push(0,ley,b[col++]);
        for(;j!=k;++j) t.modify(j->y,j->z10,j->z11);
    }
    if(col<=lex){
        t.push(0,ley,b[col++]);
        t.reset();
        for(;col<=lex;t.push(0,ley,b[col++]));
    }
}
void after(uni i,uni end){    // 块内贡献
    bt.size=1;
    bt.build();
    for(uni j=i;j<end;++j){
        qs.insert(q[j]);
        bt.x=getrk(q[j].x,dx,lex);bt.y=getrk(q[j].y,dy,ley);
        bt.z0=q[j].z00;bt.z1=q[j].z01;
        bt.z2=q[j].z10;bt.z3=q[j].z11;
        bt.ans0=bt.ans1=bt.ans2=bt.ans3=0;
        bt.get();
        write(bt.ans0);write(bt.ans1);
        write(bt.ans2);write(bt.ans3);
    }
}
int main(){
    fread(BuF,1,FSIZE,stdin);
    read(m);
    const uni BSIZE=sqrt(m*6);
    for(uni i=0;i<m;++i) q[i].get();
    for(uni i=0,end;i<m;i=end){
        end=min(m,i+BSIZE);
        dx[0]=dy[0]=1;
        for(uni j=i;j<end;++j){
            dx[j-i+1]=q[j].x;
            dy[j-i+1]=q[j].y;
        }
        lsh(dx,lex);
        lsh(dy,ley);
        before(i,end);
        after(i,end);
    }
    fwrite(WuF,1,OnF-WuF,stdout);
    fclose(stdin);
    fclose(stdout);
    return(0);
}
2022/3/16 21:13
加载中...