hdu4533 威威猫系列故事——晒被子

Problem Description

  因为马拉松初赛中吃鸡腿的题目让不少人抱憾而归,威威猫一直觉得愧对大家,这几天他悄悄搬到直角坐标系里去住了。

  生活还要继续,太阳也照常升起,今天,威威猫在第一象限晒了N条矩形的被子,被子的每条边都和坐标轴平行,不同被子的某些部分可能会叠在一起。这时候,在原点处突然发了场洪水,时间t的时候,洪水会蔓延到( t, t ),即左下角为( 0, 0 ) ,右上角为( t, t )的矩形内都有水。

  悲剧的威威猫想知道,在时间t1, t2, t3 ... tx 的时候,他有多少面积的被子是湿的?

Input

输入数据首先包含一个正整数T,表示有T组测试数据;

每组数据的第一行首先是一个整数N,表示有N条被子;

接下来N行,每行包含四个整数x1, y1, x2, y2,代表一条被子的左下角和右上角的坐标;

然后接下来一行输入一个整数x,表示有x次询问;

再接下来x行,输入x个严格单调递增的整数,每行一个,表示威威猫想知道的时间ti。

[Technical Specification]

T <= 5

0 < N <= 20000

1 <= x1 < x2 <= 200000

1 <= y1 < y2 <= 200000

1 <= x <= 20000

1 <= ti <= 200000 (1 <= i <= x )

Output

对于每次询问,请计算并输出ti时有多少面积的被子是湿的,每个输出占一行。

Sample Input

1
2
1 1 3 3
2 2 4 4
5
1
2
3
4
5

Sample Output

0
1
5
8
8

这题里求的面积是各个矩形的面积和,并不是矩形面积的并,即相互不影响,因为对于各个时段,矩形的面积都可以用A*t^2+B*t+C表示,所以我们可以用树状数组或者线段树分别维护A,B,C,每次读入一个矩形,就记录它对不同时间段t的影响,然后把相应的系数加到线段树中。

当一个矩形读入时(左下角坐标(x1,y1),右上角坐标(x2,y2)),有四种影响情况:

1.0~max(x1,y1) 这个时期因为t时间形成的矩形在该矩形下面,对面积没有影响,所以不用考虑。

2.如果存在t时间形成的矩形部分覆盖该矩形,但没有碰到或者超过该矩形的上边或者右边,那么要同时更新A,B,C,表达式为(t-x1)*(t-y1)。这里的判断表达式为如果(max(x1,y1)<min(x2,y2)),则更新max(x1,y1)~min(x2,y2)。

3.t时间内形成的矩形恰好碰到或者越过右边或上边的一条,即这段时间内的矩形面积变化中(x2-x1)或(y2-y1)为常数,那么要更新,注意,这里更新的时候要分类讨论,具体看代码。

4.max(x2,y2)~maxn,这个时期因为t时间形成的矩形已经完全覆盖矩形,所以要更新C,加上面积常数。

写线段树的时候注意,三个变量要一起存,不能开三个线段树,会超内存的。

线段树代码:
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<algorithm>
using namespace std;
#define ll __int64
#define maxn 200050
ll A,B,C;
ll a[10];
struct node{
    ll l,r,cnt1,cnt2,cnt3,flag;
}b[4*maxn];

void build(ll l,ll r,ll i)
{
    ll mid;
    b[i].l=l;b[i].r=r;b[i].cnt1=b[i].cnt2=b[i].cnt3=0;b[i].flag=1;
    if(l==r)return;
    mid=(l+r)/2;
    build(l,mid,i*2);
    build(mid+1,r,i*2+1);
}
void update(ll l,ll r,ll a[],ll i)
{
    ll mid;
    if(b[i].l==l && b[i].r==r){
        b[i].cnt1+=a[1];b[i].cnt2+=a[2];b[i].cnt3+=a[3];return;
    }
    mid=(b[i].l+b[i].r)/2;
    if(r<=mid)update(l,r,a,i*2);
    else if(l>mid)update(l,r,a,i*2+1);
    else{
        update(l,mid,a,i*2);
        update(mid+1,r,a,i*2+1);
    }
}

void question(ll id,ll i)
{
    ll mid;
    if(b[i].l==id && b[i].r==id){
        A=b[i].cnt1;B=b[i].cnt2;C=b[i].cnt3;return;
    }
    if(b[i].cnt1){
        b[i*2].cnt1+=b[i].cnt1;
        b[i*2+1].cnt1+=b[i].cnt1;
        b[i].cnt1=0;
    }
    if(b[i].cnt2){
        b[i*2].cnt2+=b[i].cnt2;
        b[i*2+1].cnt2+=b[i].cnt2;
        b[i].cnt2=0;
    }
    if(b[i].cnt3){
        b[i*2].cnt3+=b[i].cnt3;
        b[i*2+1].cnt3+=b[i].cnt3;
        b[i].cnt3=0;
    }
    mid=(b[i].l+b[i].r)/2;
    if(id<=mid)question(id,i*2);
    else question(id,i*2+1);
}

int main()
{
    ll i,j,x1,x2,y1,y2,t,t1,t2;
    int T,n,m;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        build(1,maxn,1);
        for(i=1;i<=n;i++){
            scanf("%I64d%I64d%I64d%I64d",&x1,&y1,&x2,&y2);
            if(max(x1,y1)<min(x2,y2)){
                a[1]=1;a[2]=-(x1+y1);a[3]=x1*y1;
                update(max(x1,y1),min(x2,y2)-1,a,1);
            }

            if(x2<y2){
                a[1]=0;a[2]=-x1+x2;a[3]=y1*(x1-x2);
                update(max(x2,y1),y2-1,a,1);
            }
            if(y2<x2){
                a[1]=0;a[2]=-y1+y2;a[3]=x1*(y1-y2);
                update(max(y2,x1),x2-1,a,1);
            }
            a[1]=0;a[2]=0;a[3]=(x2-x1)*(y2-y1);
            update(max(x2,y2),maxn,a,1);

        }
        scanf("%d",&m);
        for(i=1;i<=m;i++){
            scanf("%I64d",&t);
            A=B=C=0;
            question(t,1);
            printf("%I64d\n",A*t*t+B*t+C);
        }
    }
    return 0;
}

树状数组代码://速度快了一倍= =

#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 200010
#define ll __int64
using namespace std;
ll max(ll a,ll b){
	return a>b?a:b;
}
ll min(ll a,ll b){
	return a<b?a:b;
}

struct segment{
	ll b[maxn],ans;
	void clear(){
		memset(b,0,sizeof(b));
	}
	int lowbit(ll x){
		return x&(-x);
	}
	void update(ll pos,ll num){
		while(pos<=maxn){
			b[pos]+=num;pos+=lowbit(pos);
		}
	}
	ll getsum(ll pos){
		ans=0;
		while(pos>0){
			ans+=b[pos];pos-=lowbit(pos);
		}
		return ans;
	}
}A,B,C;

void fun(ll l,ll r,ll num1,ll num2,ll num3){
	A.update(l,num1);A.update(r+1,-num1);
	B.update(l,num2);B.update(r+1,-num2);
	C.update(l,num3);C.update(r+1,-num3);
}

int main()
{  

    int t;
    scanf("%d",&t);
    while(t--)
    {
        A.clear(); B.clear(); C.clear();
       int n,m;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            ll x1,y1,x2,y2;
            scanf("%I64d%I64d%I64d%I64d",&x1,&y1,&x2,&y2);  

            if(max(x1,y1)<min(x2,y2))
                fun(max(x1,y1),min(x2,y2),1,-(x1+y1),x1*y1);  

            if(x2<y2) fun(max(x2,y1)+1,y2,0,-x1+x2,y1*(x1-x2));
            if(y2<x2) fun(max(y2,x1)+1,x2,0,-y1+y2,x1*(y1-y2));  

            fun(max(x2,y2)+1,maxn,0,0,(x2-x1)*(y2-y1));
        }  

        scanf("%d",&m);
        while(m--)
        {
            ll t;
            scanf("%I64d",&t);
            ll ans=0;
            ans+=A.getsum(t)*t*t;
            ans+=B.getsum(t)*t;
            ans+=C.getsum(t);  

            printf("%I64d\n",ans);
        }
    }
    return 0;
} 

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-24 15:36:43

hdu4533 威威猫系列故事——晒被子的相关文章

HDOJ4540 威威猫系列故事——打地鼠 【DP】

威威猫系列故事--打地鼠 Time Limit: 300/100 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 1445    Accepted Submission(s): 713 Problem Description 威威猫最近不务正业,每天沉迷于游戏"打地鼠". 每当朋友们劝他别太着迷游戏,应该好好工作的时候,他总是说,我是威威猫,猫打老鼠就是我的工作! 无话

HDU 4540 威威猫系列故事——打地鼠 (DP)

威威猫系列故事——打地鼠 Time Limit: 300/100 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 1642    Accepted Submission(s): 807 Problem Description 威威猫最近不务正业,每天沉迷于游戏“打地鼠”. 每当朋友们劝他别太着迷游戏,应该好好工作的时候,他总是说,我是威威猫,猫打老鼠就是我的工作! 无话可说...

HDU 4540 威威猫系列故事――打地鼠(DP)

D - 威威猫系列故事――打地鼠 Time Limit:100MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4540 Description 威威猫最近不务正业,每天沉迷于游戏“打地鼠”.  每当朋友们劝他别太着迷游戏,应该好好工作的时候,他总是说,我是威威猫,猫打老鼠就是我的工作!  无话可说...    我们知道,打地鼠是一款经典小游戏,规则很简单:每隔一个时间

HDU - 4526 威威猫系列故事――拼车记 (DP)

Description 话说威威猫有一次去参加比赛,虽然学校离比赛地点不太远,但威威猫还是想坐出租车去.大学城的出租车总是比较另类,有"拼车"一说,也就是说,你一个人坐车去,还是一堆人一起,总共需要支付的钱是一样的(每辆出租上除司机外最多坐下4个人).刚好那天同校的一群Acmer在校门口扎堆了,大家果断决定拼车去赛场. 问题来了,一辆又一辆的出租车经过,但里面要么坐满了乘客,要么只剩下一两个座位,众Acmer都觉得坐上去太亏了,威威猫也是这么想的. 假设N名Acmer准备拼车,此时为0

【HDOJ】4516 威威猫系列故事——因式分解

可解的算法太多了,采用的算法是试x的值.注意题目的输入x^3-2x^2不会写成x^3+-2x^2.一直RE在这儿. 1 /* 4516 */ 2 #include <iostream> 3 #include <string> 4 #include <map> 5 #include <queue> 6 #include <set> 7 #include <stack> 8 #include <vector> 9 #inclu

HDU 4540 威威猫系列故事——打地鼠(简单DP)

解题思路: 水题,直接DP. #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <algorithm> #include <cmath> #include <vector> #include <queue> #include <stack> #include <set>

HDU 4504 威威猫系列故事——篮球梦(dp)

http://acm.hdu.edu.cn/showproblem.php?pid=4504 题目大意: 中文都看得懂.不过我是看hint才正确理解什么意思的.开始的时候理解错了. 解题思路: 给定时间最多是600,最多进攻次数600/15=40次,我方进攻次数40/2=20次.如果深度搜索多少种情况, 那么时间复杂度是O(3^20),直接就超时了. 我知道要动态规划,但是自己dp不行,所以就看了网上别人的解题报告. dp[i][j]=dp[i-1][j-1]+dp[i-1][j-2]+dp[i

hdu 4540 威威猫系列故事——打地鼠

http://acm.hdu.edu.cn/showproblem.php?pid=4540 dp公式: dp[i][j]=min(dp[i][j],dp[i-1][c]+abs(a[i][j]-a[i-1][c])); dp[i][j] 表示:第i时刻第j个地鼠的最小能量. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define ll long long 5 #define m

HDU ACM 4504 威威猫系列故事——篮球梦-&gt;DP

分析:d[i][j]表示前i回合获得j分的方法数. d[i][j]=d[i-1][j-1]+d[i-1][j-2]+d[i-1][j-3]. 我方最多进攻20次,每次得3分,最多20*60的状态量. #include<iostream> using namespace std; //dp[i][j]代表我方第i轮获得j分的种类数 __int64 dp[26][70]; //最大600s,600/15=40,40/2=20,最多20轮,最多得分20*3. void Init() //初始打表 {