HDU 4533 威威猫系列故事——晒被子

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4533

题意:在第一象限中给出若干矩形。现在给出一些询问,每次询问给出一个整数t,问在(0,0)到(t,t)范围的矩形面积和。

思路:参考:http://blog.csdn.net/wh2124335/article/details/8739097。经过计算可以得到,如下算法:

输入询问t
sum=0
遍历所有矩形的四个顶点
   如果该顶点在(0,0)-(t,t)的范围内
    {
          如果当前顶点是它所在矩形的左上角或右下角的点  sum-=[(t,t)和该点形成的矩形的面积]
         否则sum+=[(t,t)和该点形成的矩形的面积]
    }
返回sum
接下来进行优化:假设当前点坐标是(x,y),那么S=(t-x)*(t-y)。我们可以将其展开:S=t*t-t(x+y)+xy。因此可以将上式分成的三部分分别求和。那么我们可以将所有矩形左下角和右上角的点分到一组a(因为它们和T形成的矩形面积都是做“加”运算),把左上角和右下角的点分到一组b(因为它们和T形成的矩形面积都是做“减”运算)。那么结果可以写成sigma[a中在(t,t)范围内的点和T形成的矩形面积]-sigma[b在(t,t)范围内的点和T形成的矩形面积]。 将a,b中的点分别按max(x,y)排序。对于每次询问t,我们二分找到它在a,b中的位置n,m(即max(x,y)不超过t的最大的下标),答案就是:
Sum(Sa)-Sum(Sb)
=sigma[t*t-t*(x+y)+xy](a中点)-sigma[t*t-t*(x+y)+xy](b中点)
=[sigma(t*t)-sigma(x+y)+sigma(xy)](a中点)-[sigma(t*t)-sigma(x+y)+sigma(xy)](b中点)
然后预处理前i项即可。


struct node
{
    int x,y;

    node(){}
    node(int _x,int _y)
    {
        x=_x;
        y=_y;
    }

    int get()
    {
        return max(x,y);
    }
};

node a[N],b[N];
i64 s1[N],s2[N],f1[N],f2[N];
int n,m;

int T;

int cmp(node a,node b)
{
    return a.get()<b.get();
}


int find(node a[],int t)
{
    if(a[1].get()>t) return 0;
    if(a[2*n].get()<=t) return 2*n;
    int low=1,high=2*n,mid;
    while(low<=high)
    {
        mid=(low+high)>>1;
        if(a[mid].get()<=t) low=mid+1;
        else high=mid-1;
    }
    while(high<=2*n&&a[high].get()<=t) high++;
    return high-1;
}

void deal()
{
    int i,x,y;
    i64 ans,p,q,t;
    RD(m);
    FOR1(i,m)
    {
        RD(t);
        x=find(a,t);
        y=find(b,t);
        p=x*t*t-s1[x]*t+f1[x];
        q=y*t*t-s2[y]*t+f2[y];
        ans=p-q;
        PR(ans);
    }
}

int main()
{
    RD(T);
    while(T--)
    {
        RD(n);
        int x1,y1,x2,y2,i;
        FOR1(i,n)
        {
            RD(x1,y1,x2,y2);
            a[i*2-1]=node(x1,y1);
            a[i*2]=node(x2,y2);
            b[i*2-1]=node(x1,y2);
            b[i*2]=node(x2,y1);
        }
        sort(a+1,a+2*n+1,cmp);
        sort(b+1,b+2*n+1,cmp);
        FOR1(i,2*n)
        {
            s1[i]=s1[i-1]+a[i].x+a[i].y;
            s2[i]=s2[i-1]+b[i].x+b[i].y;
            f1[i]=f1[i-1]+(i64)a[i].x*a[i].y;
            f2[i]=f2[i-1]+(i64)b[i].x*b[i].y;
        }
        deal();
    }
    return 0;
}

  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值