【HDU5283】Senior's Fish(分块)(均摊分析)

传送门


题解:

首先是坐标切割,由于坐标移动单调,我们直接在某条鱼穿过渔网的某条线(向两端无限延伸后的)的时候重构整块。

调整块长卡常,现在是HDU rank1。

比那些写线段树的不知道快到哪里去了。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
    inline char get_char(){
        static cs int Rlen=1<<22|1;
        static char buf[Rlen],*p1,*p2;
        return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
    }
    
    template<typename T>
    inline T get(){
        char c;bool f=0;
        while(!isdigit(c=gc()))f=c=='-';T num=c^48;
        while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
        return f?-num:num;
    }
    inline int getint(){return get<int>();} 
}
using namespace IO;

using std::cerr;
using std::cout;

cs int N=1e5+7;
#define x1 x_1
#define x2 x_2
#define y1 y_1
#define y2 y_2

int n,m;
int x1,x2,y1,y2;
int B,bcnt;
int bl[N],pl[N],pr[N],ans[N];
int x[N],y[N],addx[N],addy[N],nxtx[N],nxty[N];

inline void rebuild(int id){
    ans[id]=0;nxtx[id]=0x3f3f3f3f,nxty[id]=0x3f3f3f3f;
    for(int re i=pl[id];i<=pr[id];++i){
        x[i]+=addx[id],y[i]+=addy[id];
        if(x[i]>x2||y[i]>y2)continue;
        (x1<=x[i]&&x[i]<=x2&&y1<=y[i]&&y[i]<=y2)&&(++ans[id]);
        nxtx[id]=std::min(nxtx[id],x[i]<x1?x1-x[i]:x2+1-x[i]);
        nxty[id]=std::min(nxty[id],y[i]<y1?y1-y[i]:y2+1-y[i]);
    }
    addx[id]=addy[id]=0;
}

inline void modify_x(int l,int r,int d){
    if(bl[l]==bl[r]){
        for(int re i=l;i<=r;++i)x[i]+=d;
        rebuild(bl[l]);
        return ;
    }
    if(l==pl[bl[l]])--l;
    else {
        for(int re i=l;i<=pr[bl[l]];++i)x[i]+=d;
        rebuild(bl[l]);
    }
    if(r==pr[bl[r]])++r;
    else {
        for(int re i=r;i>=pl[bl[r]];--i)x[i]+=d;
        rebuild(bl[r]);
    }
    for(int re i=bl[l]+1;i<bl[r];++i)if((addx[i]+=d)>=nxtx[i])rebuild(i);
}

inline void modify_y(int l,int r,int d){
    if(bl[l]==bl[r]){
        for(int re i=l;i<=r;++i)y[i]+=d;
        rebuild(bl[l]);
        return ;
    }
    if(l==pl[bl[l]])--l;
    else {
        for(int re i=l;i<=pr[bl[l]];++i)y[i]+=d;
        rebuild(bl[l]);
    }
    if(r==pr[bl[r]])++r;
    else {
        for(int re i=r;i>=pl[bl[r]];--i)y[i]+=d;
        rebuild(bl[r]);
    }
    for(int re i=bl[l]+1;i<bl[r];++i)if((addy[i]+=d)>=nxty[i])rebuild(i);
}

inline int query(int l,int r){int res=0;
    if(bl[l]==bl[r]){
        if(l==pl[bl[l]]&&r==pr[bl[r]])res=ans[bl[l]];
        else for(int re i=l,dx=addx[bl[l]],dy=addy[bl[l]];i<=r;++i)res+=(x1<=x[i]+dx&&x[i]+dx<=x2&&y1<=y[i]+dy&&y[i]+dy<=y2);
        return res;
    }
    if(l==pl[bl[l]])res+=ans[bl[l]];
    else{
        for(int re i=l,dx=addx[bl[l]],dy=addy[bl[l]];i<=pr[bl[l]];++i)
        res+=(x1<=x[i]+dx&&x[i]+dx<=x2&&y1<=y[i]+dy&&y[i]+dy<=y2);
    }
    if(r==pr[bl[r]])res+=ans[bl[r]];
    else {
        for(int re i=r,dx=addx[bl[r]],dy=addy[bl[r]];i>=pl[bl[r]];--i)
        res+=(x1<=x[i]+dx&&x[i]+dx<=x2&&y1<=y[i]+dy&&y[i]+dy<=y2);
    }
    for(int re i=bl[l]+1;i<bl[r];++i)res+=ans[i];
    return res;
}

inline void solve(){
    n=getint(),x1=getint(),y1=getint(),x2=getint(),y2=getint();B=std::max(1.0,sqrt(n)*0.27);bcnt=0;
    for(int re i=1;i<=n;++i){
        x[i]=getint(),y[i]=getint();
        if((i-1)%B==0){
            pl[++bcnt]=i;pr[bcnt-1]=i-1;
            addx[bcnt]=addy[bcnt]=ans[bcnt]=0;
        }
        bl[i]=bcnt;
    }bl[n+1]=bcnt+1;
    for(int re i=1;i<=bcnt;++i)rebuild(i);
    m=getint();int l,r,d;
    while(m--)switch(getint()){
        case 1:l=getint(),r=getint(),d=getint();modify_x(l,r,d);break;
        case 2:l=getint(),r=getint(),d=getint();modify_y(l,r,d);break;
        case 3:l=getint(),r=getint();cout<<query(l,r)<<"\n";break;
    }
}

signed main(){
//    freopen("fish.in","r",stdin);//freopen("fish.out","w",stdout);
    int T=getint();
    while(T--)solve(); 
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值