HDU-4533:威威猫系列故事——晒被子(线段树延迟更新+推公式)

来源:互联网 发布:vb运算符号 编辑:程序博客网 时间:2024/04/29 22:03


题目链接:点击打开链接


题目大意:

  在坐标系第一象限有多个矩形,问边长为 t 的左下角坐标(0,0)的正方形覆盖的矩形面积是多少,矩形可能重叠但是无影响。


解题思路:

 刚开始完全是蒙蔽的,甚至想到了用扫描线这种东西,后来发现不是矩形面积并。。。就傻了,去大佬博客学习了一发。。。

我是服气的,方法好强。具体做法是线段树中维护三个值 a,b,c。这个值跟面积有关,你可以理解为每个面积都可以表示为 a*t*t+b*t+c;

刚开始可能很懵,其实就是将矩形不断地加入线段树,不断更新维护线段树中a,b,c的值,线段树是以 t 的范围建的。

总体就是分情况讨论,每个矩形对于每个 t 值维护不同的a,b,c的值

(1)  t>=max(x2,y2),  对于这些 t 值,他们的 c 直接加上(x2-x1)*(y2-y1);

(2)  如果max(x1,y1)<t<min(x2,y2)(max(x1,y1)<min(x2,y2)的前提下) 就会出现矩形的一部分在正方形中,但是并没有超过矩形上边界和右边界,这时 t 范围内增加的面积就是(t-x1)*(t-y1), 化简之后就是 t*t-(x1+y1)*t+x1*y1,那么 a,b,c分别更新1  -(x1+y1)   x1*y1 就好

(3)第三种情况就是 max(min(x2,y2),max(x1,y1))<t<max(x2,y2),这里分 x2>y2 和 y2>x2 两种情况,画到图中分别是正方形超过了矩形上边界但是没有超过右边界,另外一种就是超过了右边界但是没有超过上边界。具体的公式呢可以自己推,画了图以后还是比较容易推的,需要注意的就是 维护的 a,b,c最好用 long long ,别问我咋知道的。。。

细节要注意以下边界,具体看代码吧,



#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <vector>#include <queue>#include <map>#include <algorithm>#include <stack>#include <set>#include <functional>#define rank ra#define lson rt<<1#define rson rt<<1|1#define pb push_back#define hash haha#define double intusing namespace std;typedef long long ll;const int N=200000;int n,m;ll ans;struct node{    int l,r,mid;    ll a,b,c;       //long long 型    int lazy;}t[N<<2];void build(int l,int r,int rt){    int mid=(l+r)>>1;    t[rt].l=l;t[rt].r=r;    t[rt].mid=mid;    t[rt].a=t[rt].b=t[rt].c=0;    t[rt].lazy=0;    if(l==r)        return ;    build(l,mid,lson);    build(mid+1,r,rson);}void pushdown(int rt){    if(t[rt].lazy)      //延迟更新    {        t[lson].a+=t[rt].a;        t[rson].a+=t[rt].a;        t[lson].b+=t[rt].b;        t[rson].b+=t[rt].b;        t[lson].c+=t[rt].c;        t[rson].c+=t[rt].c;        t[rt].lazy=0;        t[lson].lazy=t[rson].lazy=1;        t[rt].a=t[rt].b=t[rt].c=0;    }}void update(int l,int r,ll a,ll b,ll c,int rt)      //更新a,b,c,的值{    if(l<=t[rt].l&&t[rt].r<=r)    {        t[rt].lazy=1;        t[rt].a+=a;        t[rt].b+=b;        t[rt].c+=c;        return ;    }    pushdown(rt);    if(l<=t[rt].mid)        update(l,r,a,b,c,lson);    if(r>t[rt].mid)        update(l,r,a,b,c,rson);}void query(int k,int rt)        //单点查询{    if(t[rt].l==t[rt].r)    {        ans+=(t[rt].a*k*k+t[rt].b*k+t[rt].c);        return ;    }    pushdown(rt);    if(k<=t[rt].mid)        query(k,lson);    if(k>t[rt].mid)        query(k,rson);}int main(){    int QAQ;    scanf("%d",&QAQ);    while(QAQ--)    {        build(1,200000,1);        scanf("%d",&n);        ll x1,y1,x2,y2;        for(int i=0;i<n;i++)        {            scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);            update(max(x2,y2),N,0,0,(x2-x1)*(y2-y1),1);     //分别对应三种情况 注意边界            if(max(x1,y1)<min(x2,y2))                update(max(x1,y1),min(x2,y2)-1,1,-(x1+y1),x1*y1,1);            int k1=max(min(x2,y2),max(x1,y1)),k2=max(x2,y2);            if(x2>y2)                update(k1,k2-1,0,(y2-y1),-x1*(y2-y1),1);            if(y2>x2)                update(k1,k2-1,0,(x2-x1),-y1*(x2-x1),1);        }        scanf("%d",&m);        int k;        for(int i=0;i<m;i++)        {            ans=0;            scanf("%d",&k);     //对于每次查询输出答案            query(k,1);            cout<<ans<<endl;        }    }}



阅读全文
0 0