HDU 5283 Senior ' s Fish

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5283
思路:这题的离线做法非常简单不必多说,我想说的是在线做法。。。因为我太傻逼一开始没有意识到这是个离线问题。
在线的话就是分块,我们进行序列分块,对横纵坐标分开维护,注意到一个点只会进出一次,就拿横坐标举例,我们使块内有序,维护一个块的指针 L R,分别表示大于等于 x1 的最小的位置和小于等于 x2 的最大的位置,那么点的进出只和 L,R 相关,考虑修改的话就是对于中间的块打标记并暴力移动 L,R ,注意到这一步总的时间是 O(n) 因为每个点只会进出矩形一次。对于边界上的我们将块暴力重构,然而维护有序性直接排序是带 log 的,注意到我们归并一下就好了。
代码因为边界调的我意识模糊。。。
复杂度: O(nn)

代码:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
//#include<cmath> 
#define N 100002
#define M 502
using namespace std;
int n,m,x[N],y[N],Xtag[M],Ytag[M],XL[M],XR[M],YL[M],YR[M],num[M],l,r,d,
belong[N],bl[M],br[M],XID[N],YID[N],ll,rr,Q[N],x1,x2,y1,y2,B,cnt,tm;
bool in[N];
//对每个块,tag[i]表示块i的标记,L[i]表示出现点,R[i]表示消失点
//分别按x,y维护,再实时维护一个没有标记的坐标,num[i]表示块i的和 
//belong = (i - 1) / B
inline void ino(int &xx)
{
    char c; int sy = 1;
    while (!isdigit(c = getchar()))
      if (c == '-') sy = -1;
    xx = (c ^ 48);
    while (isdigit(c = getchar())) xx = 10 * xx + (c ^ 48);
    xx *= sy;
}

inline bool cmp1(int a,int b)
{
    return x[a] < x[b];
}

inline bool cmp2(int a,int b)
{
    return y[a] < y[b];
}

inline void X_rebuild(int i)
{
        int j;
        Xtag[i] = 0; num[i] = 0;
        j = bl[i];
        for (;j <= br[i]&&x[XID[j]] < x1; ++j);
        XL[i] = j;
        j = br[i];
        for (;j >= bl[i]&&x[XID[j]] > x2; --j);
        XR[i] = j;
        for (j = bl[i];j <= br[i]; ++j)
        {
          if (x[j] >= x1&&x[j] <= x2&&y[j] >= y1&&y[j] <= y2) in[j] = 1,num[i]++;
          else in[j] = 0;
        }
}

inline void Y_rebuild(int i)
{
        int j;
        Ytag[i] = 0; num[i] = 0;
        j = bl[i];
        for (;j <= br[i]&&y[YID[j]] < y1; ++j);
        YL[i] = j;
        j = br[i];
        for (;j >= bl[i]&&y[YID[j]] > y2; --j);
        YR[i] = j;
        for (int j = bl[i];j <= br[i]; ++j)
          if (x[j] >= x1&&x[j] <= x2&&y[j] >= y1&&y[j] <= y2) in[j] = 1,num[i]++;
          else in[j] = 0;
}

inline void init()
{
    ino(n);
    ino(x1); ino(y1); ino(x2); ino(y2);
    for (int i = 1;i <= n; ++i) ino(x[i]),ino(y[i]);
    for (B = 1;B * B <= n; ++B);
    for (int i = 1;i <= n;++i) belong[i] = (i - 1) / B;
    belong[n + 1] = n / B + 1;
    memset(Xtag,0,sizeof(Xtag));
    memset(Ytag,0,sizeof(Ytag));
    memset(in,0,sizeof(in)); 
    belong[0] = -1;
    for (int i = 1;i <= n; ++i) 
    {
        if (belong[i] != belong[i - 1]) bl[belong[i]] = i;
        if (belong[i] != belong[i + 1]) br[belong[i]] = i;
    }
    cnt = (n - 1) / B;
    for (int i = 1;i <= n; ++i) XID[i] = i,YID[i] = i;
    for (int i = 0;i <= cnt; ++i) 
    {
       sort(XID + bl[i],XID + br[i] + 1,cmp1);
       sort(YID + bl[i],YID + br[i] + 1,cmp2);
       X_rebuild(i);
       Y_rebuild(i);
    }
}

inline bool pd(int P,int al,int ar)
{
    return (P >= al&&P <= ar);
}

inline void X_merge(int blo,int lo,int ro)
{
    for (int i = bl[blo];i <= br[blo]; ++i) x[XID[i]] += Xtag[blo] + (pd(XID[i],lo,ro) ? d : 0),y[YID[i]] += Ytag[blo];
    Xtag[blo] = 0; Ytag[blo] = 0;
    int p = bl[blo],q = bl[blo];
    for (;p <= br[blo]&&!pd(XID[p],lo,ro);++p);
    for (;q <= br[blo]&&pd(XID[q],lo,ro);++q);
    for (int i = bl[blo];i <= br[blo]; ++i)
    {
        if (q > br[blo]||p <= br[blo]&&x[XID[p]] < x[XID[q]])
        {   
            Q[i] = XID[p++];
            for (;p <= br[blo]&&!pd(XID[p],lo,ro); ++p);
        }
        else
        {
            Q[i] = XID[q++];
            for (;q <= br[blo]&&pd(XID[q],lo,ro); ++q);
        }
    }
    for (int i = bl[blo];i <= br[blo]; ++i) XID[i] = Q[i];
}

inline void X_Deal_middle()
{
    for (int i = ll + 1;i < rr; ++i) 
    {
        Xtag[i] += d;
        int j; 
        for (j = XR[i];j >= bl[i]&&x[XID[j]] + Xtag[i] > x2; --j)
            if (in[XID[j]]) --num[i],in[XID[j]] = 0;
        XR[i] = j; 
        for (j = XL[i] - 1;j >= bl[i]&&x[XID[j]] + Xtag[i] >= x1; --j)
            if (y[XID[j]] + Ytag[i] <= y2&&y[XID[j]] + Ytag[i] >= y1&&x[XID[j]] + Xtag[i] <= x2&&!in[XID[j]]) ++num[i],in[XID[j]] = 1;
        XL[i] = j + 1;
    }
}

inline void X_()
{
    ino(d);
    ll = belong[l]; rr = belong[r];
    X_Deal_middle();
    if (ll != rr)
    {
        X_merge(ll,l,br[ll]);
        X_rebuild(ll);
        X_merge(rr,bl[rr],r);
        X_rebuild(rr);
    }
    else
    {
        X_merge(ll,l,r);
        X_rebuild(ll);
    }
}

inline void Y_Deal_middle()
{
    for (int i = ll + 1;i < rr; ++i) 
    {
        Ytag[i] += d;
        int j;
        for (j = YR[i];j >= bl[i]&&y[YID[j]] + Ytag[i] > y2; --j)
            {
            if (in[YID[j]]) --num[i],in[YID[j]] = 0;}
        YR[i] = j;
        for (j = YL[i] - 1;j >= bl[i]&&y[YID[j]] + Ytag[i] >= y1; --j)
            if (x[YID[j]] + Xtag[i] <= x2&&x[YID[j]] + Xtag[i] >= x1&&y[YID[j]] + Ytag[i] <= y2&&!in[YID[j]]) ++num[i],in[YID[j]] = 1;
        YL[i] = j + 1;
    }
}

void Y_merge(int blo,int lo,int ro)
{
    for (int i = bl[blo];i <= br[blo]; ++i) y[YID[i]] += Ytag[blo] + (pd(YID[i],lo,ro) ? d : 0),x[XID[i]] += Xtag[blo];
    Ytag[blo] = 0; Xtag[blo] = 0;
    int p = bl[blo],q = bl[blo];
    for (;p <= br[blo]&&!pd(YID[p],lo,ro);++p);
    for (;q <= br[blo]&&pd(YID[q],lo,ro);++q);
    for (int i = bl[blo];i <= br[blo]; ++i)
    {
        if (q > br[blo]||p <= br[blo]&&y[YID[p]] < y[YID[q]])
        {   
            Q[i] = YID[p++];
            for (;p <= br[blo]&&!pd(YID[p],lo,ro); ++p);
        }
        else
        {
            Q[i] = YID[q++];
            for (;q <= br[blo]&&pd(YID[q],lo,ro); ++q);
        }
    }
    for (int i = bl[blo];i <= br[blo]; ++i) YID[i] = Q[i];
}

inline void Y_()
{
    ino(d);
    ll = belong[l]; rr = belong[r];
    Y_Deal_middle();
    if (ll != rr)
    {
        Y_merge(ll,l,br[ll]);
        Y_rebuild(ll);
        Y_merge(rr,bl[rr],r);
        Y_rebuild(rr);
    }
    else
    {
        Y_merge(ll,l,r);
        Y_rebuild(ll);
    }
}

inline void Q_()
{
    int S = 0;
    int ll = belong[l],rr = belong[r];
    for (int i = ll + 1;i < rr; ++i) S += num[i];
    if (ll == rr) 
        for (int i = l;i <= r; ++i) S += in[i];
        else
        {
    int t = br[belong[l]];
    for (int i = l;i <= t; ++i) S += in[i];
    t = bl[belong[r]];
    for (int i = r;i >= t; --i) S += in[i];
    }   
    printf("%d\n",S);
}

inline void DO_IT()
{
    int ty;
    ino(m);
    tm = 0;
    for (;m;--m)
    {
        ino(ty); ino(l); ino(r);
        if (ty == 1) X_();
        if (ty == 2) Y_();
        if (ty == 3) Q_();
    }
}

int main()
{
    //freopen("test.in","r",stdin);
    //freopen("test.out","w",stdout);
    init();
    DO_IT(); 
    fclose(stdin); fclose(stdout);
    return 0;
}
/*
   5
   1 1 5 5
   1 1
   2 2
   3 3
   4 4
   5 5
   3
   3 1 5
   1 2 4 2
   3 1 5
*/

总结:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值