题意:

给出的区域,每个格子最开始是白色的,现在有q次操作,每次操作对于给定的,把满足的格子涂成黑色。问在q次操作后区域中白色格子的个数。其中

思路:

自己做的时候想到每个圆覆盖的整数点可以变成菱形,所以想到了矩形面积并,还觉得是不是要变换坐标系,整个都跑偏了…

其实考虑到数据范围很小,直接扫描线就可以了。

枚举,遍历每个操作,可以求出这条扫描线与每个圆相交的区间,存入vector,再将这些区间按照左端点进行排序,然后问题就转化为这些区间覆盖的点的个数了,只要维护最右边的点R就可以了。

复杂度是似乎跑得蛮快啊?

写的时候仔细一点,注意我代码里注释的那个点。

代码:

struct node
{
    int l,r;
};
vector<node>v;
int r[210][3];
bool cmp(node x,node y)
{
    if(x.l!=y.l)return x.l<y.l;
    return x.r<y.r;
}
int main()
{
    int t,n,m,q;
    node temp;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&q);
        for(int i=0;i<q;i++)
            scanf("%d%d%d",&r[i][0],&r[i][1],&r[i][2]);
        int ans=n*m;
        for(int i=0;i<n;i++)
        {
            v.clear();
            for(int j=0;j<q;j++)
            {
                int lx=max(0,r[j][0]-r[j][2]),rx=min(n-1,r[j][0]+r[j][2]);
                if(i<lx||i>rx)continue;
                //printf("(%d,%d)(%d,%d)\n",i,j,lx,rx);
                int d=abs(i-r[j][0]);
                //printf("d:%d\n",d);
                int dd=(int)floor(sqrt(1.0*r[j][2]*r[j][2]-d*d));
                //printf("dd:%d\n",dd);
                temp.l=max(0,r[j][1]-dd);
                temp.r=min(m-1,r[j][1]+dd);
                //printf("%d %d\n",temp.l,temp.r);
                v.push_back(temp);
            }
            int len=v.size();
            if(len==0)continue;
            sort(v.begin(),v.end(),cmp);
            int R=v[0].r;
            ans-=v[0].r-v[0].l+1;
            for(int j=0;j<len;j++)
            {
                if(v[j].r<=R)continue;
                if(v[j].l<=R)ans-=v[j].r-R;
                //这里注意不用+1,因为之前已经算过R这个点了,因为这个WA了一发...
                else ans-=v[j].r-v[j].l+1;
                R=v[j].r;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

HDU6535 倒着的ST表 Previous
上海大都会赛A 随机 Next