【未知来源】火神的鱼

题意

  二维平面上有 \(n\) 个点,有一个四边平行于坐标轴的渔网,同时平面上有 \(n\) 个编号为 \(1\)\(n\) 点。
  你需要支持 \(3\) 种操作:
    1 l r d:编号在 \([l,r]\) 内的所有点向 \(x\) 轴正方向平移 \(d\) 个单位
    1 l r d:编号在 \([l,r]\) 内的所有点向 \(y\) 轴正方向平移 \(d\) 个单位
    3 l r:求渔网内有多少个点(在渔网边界上的点也算)
  \(T\in [1,10]\) 组数据,\(1\le n,m\le 30000,\space 1\le d\le 10^9,\space x_1\le x_2,\space y_1\le y_2\)

题解

  普及题,把渔网拆成 \(4\) 个左下角无限远的矩形,每个子问题变成只限制点的 \(x,y\) 坐标上限,每次操作前把越界的点删掉即可,这就只需要线段树支持单点删除和求区间最大值。最后容斥一下 \(4\) 个矩形的答案。

  还是只想存下题。

#include<bits/stdc++.h>
#define ll long long
#define N 30005
#define lowbit(x) x&-x
const ll inf = 1e9 + 7;
using namespace std;
inline int read(){
    int x=0; bool f=1; char c=getchar();
    for(;!isdigit(c); c=getchar()) if(c=='-') f=0;
    for(; isdigit(c); c=getchar()) x=(x<<3)+(x<<1)+(c^'0');
    if(f) return x; return 0-x;
}
 
int n,m,x1,Y1,x2,y2,p[N][2],ans[N];
struct query{int opt,l,r,d;}q[N];
struct SegTree{
    #define ls o<<1
    #define rs o<<1|1
    ll mx[N<<2],tag[N<<2];
    inline void pushdown(int o){
        if(tag[o]){
            mx[ls]+=tag[o], mx[rs]+=tag[o];
            tag[ls]+=tag[o], tag[rs]+=tag[o];
            tag[o]=0;
        }
    }
    inline void pushup(int o){
        mx[o]=max(mx[ls],mx[rs]);
    }
    void build(int o, int l, int r, int opt){
        tag[o]=0;
        if(l==r){mx[o]=p[l][opt]; return;}
        int mid=(l+r)>>1;
        build(ls,l,mid,opt);
        build(rs,mid+1,r,opt);
        pushup(o);
    }
    void mdf(int o, int l, int r, int L, int R, ll v){
        if(L<=l && r<=R){
            mx[o]+=v, tag[o]+=v;
            return;
        }
        pushdown(o);
        int mid=(l+r)>>1;
        if(L<=mid) mdf(ls,l,mid,L,R,v);
        if(R>mid) mdf(rs,mid+1,r,L,R,v);
        pushup(o);
    }
    int query(int o, int l, int r){
        if(l==r) return l;
        pushdown(o);
        int mid=(l+r)>>1;
        return mx[ls]>mx[rs] ? query(ls,l,mid) : query(rs,mid+1,r);
    }
}tx,ty;
 
int fwk[N];
void ins(int x,int v){for(; x<=n; x+=lowbit(x)) fwk[x]+=v;}
int ask(int x){
    int res=0;
    for(; x; x-=lowbit(x)) res+=fwk[x];
    return res;
}
 
void calc(int x, int y, int v){
    tx.build(1,1,n,0);
    ty.build(1,1,n,1);
    memset(fwk,0,sizeof(fwk));
    for(int i=1; i<=n; i++) ins(i,1);
    for(int i=1; i<=m; i++){
        while(tx.mx[1]>x){
            int p=tx.query(1,1,n);
            tx.mdf(1,1,n,p,p,-inf);
            if(ask(p)-ask(p-1)) ins(p,-1);
        }
        while(ty.mx[1]>y){
            int p=ty.query(1,1,n);
            ty.mdf(1,1,n,p,p,-inf);
            if(ask(p)-ask(p-1)) ins(p,-1);
        }
        if(q[i].opt==1) tx.mdf(1,1,n,q[i].l,q[i].r,(ll)q[i].d);
        if(q[i].opt==2) ty.mdf(1,1,n,q[i].l,q[i].r,(ll)q[i].d);
        if(q[i].opt==3) ans[i] += v*(ask(q[i].r)-ask(q[i].l-1));
    }
}
signed main(){
    //freopen("c.in","r",stdin);
    //freopen("std.out","w",stdout);
    int T=read();
    while(T--){
        n=read();
        x1=read(), Y1=read(), x2=read(), y2=read();
        for(int i=1; i<=n; i++) p[i][0]=read(), p[i][1]=read();
        m=read();
        for(int i=1; i<=m; i++){
            q[i].opt=read(), q[i].l=read(), q[i].r=read();
            if(q[i].opt!=3) q[i].d=read();
            ans[i]=0;
        }
        calc(x2,y2,1);
        calc(x1-1,Y1-1,1), calc(x2,Y1-1,-1), calc(x1-1,y2,-1);
        for(int i=1;i<=m;i++) if(q[i].opt==3) printf("%d\n",ans[i]);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/scx2015noip-as-php/p/11424308.html