【hihocoder1249 2015北京赛区A】【打标记线性扫描法】 Xiongnu's Land 土地划分使得左边比右边大且尽可能接近

#include<stdio.h>
#include<string.h>
typedef long long LL;
const int N=1e6+10;
int n,g;
int y,x,w,h;
int a[N];
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        LL sum=0;
        scanf("%d",&n);
        memset(a,0,sizeof(a));
        scanf("%d",&g);
        for(int i=1;i<=g;i++)
        {
            scanf("%d%d%d%d",&x,&y,&w,&h);
            a[x]+=h;
            a[x+w]-=h;
            sum+=(LL)w*h;
        }
        LL bot=(sum+1)/2;
        LL tmp=0;
        int add=0;
        for(int i=1;i<n;i++)
        {
            add+=a[i];
            tmp+=add;

			//一旦达到了条件1,我们就在满足条件2的情况下尽可能右移分界线
            if(tmp>=bot)
			{
				while(++i<n)
				{
					add+=a[i];
					if(add)break;
				}
				printf("%d\n",i);
				break;
			}
        }
    }
}
/*
【trick&&吐槽】
1,打标记的数组表示横坐标每右移一位所产生的增益。数值不会超过n,用int数组存即可。

【题意】
T(1<=T<=15)组数据,
对于每组数据,给你一个大小为n*n(1<=n<=1e6)的地图,左下角为(0,0),右上角为(n,n)
然后有g(1<=g<=10000)块绿洲,坐落在这个地图上,不相交不溢出。
然后我们告诉你每块绿洲的坐标(通过给出左上角坐标及长与宽的形式)。
让你把这个地图以某个横坐标x'为界限,划分为2部分(甚至可能其中一部分的面积为0)。
使得
1,(x=x')这条线左边绿洲的面积>=(x=x')这条线右边绿洲的面积
2,在1的条件下,(x=x')这条线左边绿洲的面积与这条线右边绿洲的面积尽可能接近
3,在1和2的条件下,(x=x')这条线左边地图的面积尽可能大。

【类型】
贪心,线性扫描。

【分析】
这道题数据组数15,每组的横坐标数为1e6。
于是我们很自然地想到,如果有15*1e6的做法,这道题就可以做完了。

给定的是矩形面积,然而我们可以通过打标记的方法把它转化为线性扫描
每个绿洲,给出(x,y,w,h),
那如果我们选择的这条线在[x,x+w)范围内,每右移1,绿洲面积就会增加h,
我们的实现方法是,打标记。
那么对于一个(x,y,w,h)的绿洲,标记打为a[x]+=h,a[x+w]-=h;
表示在[x,x+w)范围内,线每右移1,绿洲面积增加h,然后在x+w和其之后,再右移就没有这个增效了。
这样我们从前向后扫描,扫描到一个>=half绿洲面积的最右位置,这道题就做完啦。

【时间复杂度&&优化】
O(Tn)

*/

你可能感兴趣的:(hihocoder1249)