CodeForces 15D Map

Description

There is an area map that is a rectangular matrix n × m, each cell of the matrix contains the average height of a corresponding area part. Peter works for a company that has to build several cities within this area, each of the cities will occupy a rectangle a × b cells on the map. To start construction works in a particular place Peter needs to remove excess ground from the construction site where a new city will be built. To do so he chooses a cell of the minimum height within this site, and removes excess ground from other cells of the site down to this minimum level. Let's consider that to lower the ground level from h2 to h1 (h1 ≤ h2) they need to remove h2 - h1 ground units.

Let's call a site's position optimal, if the amount of the ground removed from this site is minimal compared to other possible positions. Peter constructs cities according to the following algorithm: from all the optimum site's positions he chooses the uppermost one. If this position is not unique, he chooses the leftmost one. Then he builds a city on this site. Peter repeats this process untill he can build at least one more city. For sure, he cannot carry out construction works on the occupied cells. Would you, please, help Peter place cities according to the algorithm?

Input

The first line contains four space-separated integers: map sizes nm and city sizes ab (1 ≤ a ≤ n ≤ 10001 ≤ b ≤ m ≤ 1000). Then there follow n lines, each contains m non-negative space-separated numbers, describing the height matrix. Each number doesn't exceed 109.

Output

In the first line output k — the amount of constructed cities. In each of the following k lines output 3 space-separated numbers — the row number and the column number of the upper-left corner of a subsequent construction site, and the amount of the ground to remove from it. Output the sites in the order of their building up.

Sample Input

Input
2 2 1 2
1 2
3 5
Output
2
1 1 1
2 1 2
Input
4 4 2 2
1 5 3 4
2 7 6 1
1 1 2 2
2 2 1 2
Output
3
3 1 2
3 3 3

1 2 9

两次rmq求出矩形区域的最小值,然后对于每个点,按花费排序,一个一个删除,在二维树状数组中标记。

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<string>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
typedef long long LL;
const int low(int x){return x&-x;}
const int maxn=1e3+10;
int n,m,a,b,h[maxn][maxn],tot;
int f[maxn][maxn],dp[maxn][20];
int flag[maxn][maxn];
LL sum[maxn][maxn];
int u[maxn*maxn];

struct point
{
    int x,y;
    LL c;
    bool operator<(const point& a)const
    {
        return c==a.c?x==a.x?y<a.y:x<a.x:c<a.c;
    }
    point(int x=0,int y=0,LL c=0):x(x),y(y),c(c){};
}c[maxn*maxn];

int get(int x,int y)
{
    int ans=0;
    for (int i=x;i;i-=low(i))
        for (int j=y;j;j-=low(j)) ans+=flag[i][j];
    return ans;
}

void add(int x,int y,int z)
{
    for (int i=x;i<=n;i+=low(i))
        for (int j=y;j<=m;j+=low(j)) flag[i][j]+=z;
}

int main()
{
    while(~scanf("%d%d%d%d",&n,&m,&a,&b))
    {
        tot=0;  memset(flag,0,sizeof(flag));
        for (int i=1;i<=n;i++)
        {
            for (int j=1;j<=m;j++)
            {
                scanf("%d",&h[i][j]);
                sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+h[i][j];
                dp[j][0]=h[i][j];
            }
            for (int k=1;(1<<k)<=b;k++)
            {
                for (int j=1;j<=m;j++)
                {
                    dp[j][k]=min(dp[j][k-1],dp[j+(1<<k-1)][k-1]);
                }
            }
            int k=log(1.0*b)/log(2.0);
            for (int j=1;j<=m-b+1;j++)
            {
                f[i][j]=min(dp[j][k],dp[j+b-(1<<k)][k]);
            }
        }
        for (int i=1;i<=m-b+1;i++)
        {
            for (int j=1;j<=n;j++) dp[j][0]=f[j][i];
            for (int k=1;(1<<k)<=a;k++)
            {
                for (int j=1;j<=n;j++)
                {
                    dp[j][k]=min(dp[j][k-1],dp[j+(1<<k-1)][k-1]);
                }
            }
            int k=log(1.0*a)/log(2.0);
            for (int j=1;j<=n-a+1;j++)
            {
                LL cost=min(dp[j][k],dp[j+a-(1<<k)][k]);
                LL s=sum[j-1][i-1]+sum[j-1+a][i-1+b]-sum[j-1][i-1+b]-sum[j-1+a][i-1];
                s-=cost*a*b;
                u[tot]=0;
                c[tot++]=point(j,i,s);
            }
        }
        sort(c,c+tot);
        int cnt=0;
        for (int i=0;i<tot;i++)
        {
            if (get(c[i].x,c[i].y)) continue;
            if (get(c[i].x+a-1,c[i].y)) continue;
            if (get(c[i].x,c[i].y+b-1)) continue;
            if (get(c[i].x+a-1,c[i].y+b-1)) continue;
            u[i]=1; cnt++;
            add(c[i].x,c[i].y,1);
            add(c[i].x+a,c[i].y+b,1);
            add(c[i].x,c[i].y+b,-1);
            add(c[i].x+a,c[i].y,-1);
        }
        printf("%d\n",cnt);
        for (int i=0;i<tot;i++)
            if (u[i]) printf("%d %d %lld\n",c[i].x,c[i].y,c[i].c);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值