首页 > 技术文章 > 题解 洛谷 P4203 【[NOI2008]糖果雨】

lhm- 2020-08-27 08:27 原文

发现任何时刻不会出现两片颜色相同的云朵,因此云朵的颜色是不用考虑的,询问即为区间内有多少个云朵。

因为云朵的运动是在天空中往返的,具有周期性,且每个云朵运动速度都相同,所以可以用二元组 \((time,lenth)\) 来表示一个云朵,\(time\) 为该云朵左端点位于左边界时的时刻,即 \(t-ld \bmod 2len\)\(lenth\) 为该云朵的长度,即 \(r-l\),发现每个云朵都能用二维平面上的点 \((x,y)\) 来表示。

接着考虑如何解决询问 \((t,l,r)\),首先对 \(t\) 转化为 \(t \bmod 2len\)。然后通过分类讨论来找到对于该询问在二维平面上对应的位置。设云朵的坐标为 \((x,y)\),得:

\(t \geqslant x\) 时,该云朵要到达询问的时刻还需再经过一段时间,经过这些时间后云朵的左端点要在询问的右端点左边,即 \(t-x \leqslant r\),云朵的右端点要在询问的左端点右边,即 \(t-x+y \geqslant l\)

\(t < x\) 时,该云朵已经超过询问的时刻,因此其需要时光倒流,因为运动的周期性,其还是向右运动,把这些时间倒流后云朵的左端点要在询问的右端点左边,即 \(x-t \leqslant r\),云朵的右端点要在询问的左端点右边,即 \(x-t+y \geqslant l\)

综上所述得询问在二维平面上对应的位置为 \(t-r \leqslant x \leqslant t+r,| x-t | +y \geqslant l\),在平面上画出图来得:

发现图像为两个对称的五边形,若其超出了边界,就在另一端补上来,对于该图像不好进行统计,因此还需再进行转化,将其补成平行四边形得:

然后考虑对这两个平行四边形转化为矩形来进行统计,因为是询问存在性,而不是面积之类的信息,所以对于询问的范围进行转化,对于每个云朵的坐标也进行转化,然后进行询问就是合法的。对于右边向右倾斜的平行四边形,对其应用变换 \((x,y) \Rightarrow (x,x+y)\),对于左边向左倾斜的平行四边形,对其应用变换 \((x,y) \Rightarrow (x,y-x+2len)\),这里加上 \(2len\) 的原因是防止出现负坐标。然后对于这两个平行四边形分别用两个二维树状数组来维护,每个云朵在树状数组上进行加点删点时也应用相应的变换即可。

注意到当询问出现 \(r=len\) 的情况时,\(t-r\)\(t+r\) 这两个位置会算重,因此需要特判。

#include<bits/stdc++.h>
#define maxn 4010
#define maxm 1000010
#define lowbit(x) (x&(-x))
using namespace std;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,len;
struct node
{
    int x,y;
}p[maxm];
struct BIT
{
    int t[maxn][maxn];
    void update(int x,int y,int v)
    {
        for(int i=x+1;i<=2*len;i+=lowbit(i))
            for(int j=y+1;j<=4*len;j+=lowbit(j))
                t[i][j]+=v;
    }
    int ask(int x,int y)
    {
        if(x<0||y<0) return 0;
        int v=0;
        for(int i=min(x+1,2*len);i;i-=lowbit(i))
            for(int j=min(y+1,4*len);j;j-=lowbit(j))
                v+=t[i][j];
        return v;
    }
    int query(int x1,int y1,int x2,int y2)
    {
        return ask(x2,y2)-ask(x2,y1-1)-ask(x1-1,y2)+ask(x1-1,y1-1);
    }
}T1,T2;
int main()
{
    read(n),read(len);
    for(int i=1;i<=n;++i)
    {
        int opt,t,c,l,r,d,v=0;
        read(opt);
        if(opt==1)
        {
            read(t),read(c),read(l),read(r),read(d);
            p[c].x=(t-l*d+2*len)%(2*len),p[c].y=r-l;
            T1.update(p[c].x,p[c].x+p[c].y,1),T2.update(p[c].x,p[c].y-p[c].x+2*len,1);
        }
        if(opt==2)
        {
            read(t),read(l),read(r),d=(r==len),t%=2*len;
            v+=T1.query(t,t+l,t+r-d,4*len);
            v+=T1.query(0,t+l-2*len,t+r-2*len,4*len);
            v+=T2.query(t-r+d,l-t+2*len,t-1,4*len);
            v+=T2.query(t-r+2*len,l-t,2*len,4*len);
            printf("%d\n",v);
        }
        if(opt==3)
        {
            read(t),read(c);
            T1.update(p[c].x,p[c].x+p[c].y,-1),T2.update(p[c].x,p[c].y-p[c].x+2*len,-1);
        }
    }
    return 0;
}

推荐阅读