HDU 4819 二维线段树

HDU 4819
题目链接:
http://www.bnuoj.com/v3/problem_show.php?pid=35690
题意:
给一个初始矩阵,矩阵大小1000 * 1000。
现在有一个操作询问以(i,j)为中心的正方形(保证边长为奇数)中矩阵格子里的最大值和最小值,输出(max+min)/2,并且把这个格子变成这个值。
思路:
裸二维线段树,其实是自己想的写法居然和大多数版差不多……这个版写的还是太繁琐,建议直接用大白书上的版。
源码:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#define inf (1000000007)
typedef pair<int,int> pii;
const int MAXN = 800 + 5;
int mmin[MAXN * 4][MAXN * 4], mmax[MAXN * 4][MAXN * 4];
int a[MAXN][MAXN];
int n;
int temp;
pii change(pii a, pii b)
{
    pii ans;
    ans.first = min(a.first, b.first);
    ans.second = max(a.second, b.second);
    return ans;
}
void push_upx(int ox, int oy)
{
    mmin[ox][oy] = min(mmin[ox << 1][oy], mmin[(ox << 1) + 1][oy]);
    mmax[ox][oy] = max(mmax[ox << 1][oy], mmax[(ox << 1) + 1][oy]);
}
void push_upy(int ox, int oy)
{
    mmin[ox][oy] = min(mmin[ox][oy << 1], mmin[ox][(oy << 1) + 1]);
    mmax[ox][oy] = max(mmax[ox][oy << 1], mmax[ox][(oy << 1) + 1]);
}
void buildy(int ox, int lx, int rx, int oy, int ly, int ry)
{
    temp = max(temp, oy);
    if(lx == rx){
        if(ly == ry) mmin[ox][oy] = mmax[ox][oy] = a[lx][ly];
        else{
            int mid = (ly + ry) >> 1;
            buildy(ox, lx, rx, (oy << 1), ly, mid);
            buildy(ox, lx, rx, (oy << 1) + 1, mid + 1, ry);
            push_upy(ox, oy);
        }
    }
    else{
        if(ly == ry) push_upx(ox, oy);
        else{
            int mid = (ly + ry) >> 1;
            buildy(ox, lx, rx, (oy << 1), ly, mid);
            buildy(ox, lx, rx, (oy << 1) + 1, mid + 1, ry);
            push_upx(ox, oy);
        }
    }
}
void buildx(int ox, int lx, int rx)
{
    if(lx != rx){
        int mid = (lx + rx) >> 1;
        buildx(ox << 1, lx, mid);
        buildx((ox << 1) + 1, mid + 1, rx);
    }
    buildy(ox, lx, rx, 1, 1, n);
}
void updatey(int ox, int lx, int rx, int oy, int ly, int ry, int y, int val)
{
//    printf("updatey ox = %d, oy = %d, ly = %d, ry = %d, y = %d, val = %d\n", ox, oy, ly, ry, y, val);
    if(lx == rx){
        if(ly == ry) mmin[ox][oy] = mmax[ox][oy] = val;
        else{
            int mid = (ly + ry) >> 1;
            if(y <= mid) updatey(ox, lx, rx, oy << 1, ly, mid, y, val);
            else updatey(ox, lx, rx, (oy << 1) + 1, mid + 1, ry, y, val);
            push_upy(ox, oy);
        }
    }
    else{
        if(ly == ry) push_upx(ox, oy);
        else{
            int mid = (ly + ry) >> 1;
            if(y <= mid) updatey(ox, lx, rx, oy << 1, ly, mid, y, val);
            else updatey(ox, lx, rx, (oy << 1) + 1, mid + 1, ry, y, val);
            push_upy(ox, oy);
        }
    }
}
void updatex(int ox, int lx, int rx, int x, int y, int val)
{
//    printf("udpatex ox = %d, lx = %d, rx = %d, x = %d, y = %d, val = %d\n", ox, lx, rx, x, y, val);
//    if(val == 6) printf("ox = %d, lx = %d, rx = %d")
    if(lx == rx){
        updatey(ox, lx, rx, 1, 1, n, y, val);
    }
    else{
        int mid = (lx + rx) >> 1;
        if(x <= mid) updatex(ox << 1, lx, mid, x, y, val);
        else updatex((ox << 1) + 1, mid + 1, rx, x, y, val);
        updatey(ox, lx, rx, 1, 1, n, y, val);
    }
}
pii queryy(int ox, int oy, int ly, int ry, int y, int L)
{
    pii ans = make_pair(inf, -inf);
    int y1 = y - L / 2; int y2 = y + L / 2;
    if(ly >= y1 && ry <= y2) ans = make_pair(mmin[ox][oy], mmax[ox][oy]);
    else{
        int mid = (ly + ry) >> 1;
        if(y1 <= mid) ans = change(ans, queryy(ox, oy << 1, ly, mid, y, L));
        if(y2 > mid) ans = change(ans, queryy(ox, (oy << 1) + 1, mid + 1, ry, y, L));
    }
    return ans;
}
pii queryx(int ox, int lx, int rx, int x, int y, int L)
{
    pii ans = make_pair(inf, -inf);
    int x1 = x - L / 2; int x2 = x + L / 2;
    if(lx >= x1 && rx <= x2) ans = queryy(ox, 1, 1, n, y, L);
    else{
        int mid = (lx + rx) >> 1;
        if(x1 <= mid) ans = change(ans, queryx(ox << 1, lx, mid, x, y, L));
        if(x2 > mid) ans = change(ans, queryx((ox << 1) + 1, mid + 1, rx, x, y, L));
    }
    return ans;
}
int main()
{
    int T;
    scanf("%d", &T);
    for(int cas = 1 ; cas <= T ; cas++){
        scanf("%d", &n);
        for(int i = 1 ; i <= n ; i++) for(int j = 1 ; j <= n ; j++) scanf("%d", &a[i][j]);
        temp = 0;
        buildx(1, 1, n);
        int q;
        printf("Case #%d:\n", cas);
        scanf("%d", &q);
        while(q--){
            int u, v, L;
            scanf("%d%d%d", &u, &v, &L);
            pii ans = queryx(1, 1, n, u, v, L);
//            printf("ans.first = %d, ans.second = %d\n", ans.first, ans.second);
            a[u][v] = (ans.second + ans.first) / 2;
            printf("%d\n", a[u][v]);
            updatex(1, 1, n, u, v, a[u][v]);

//            for(int i = 1 ; i <= 5 ; i++){
//                for(int j = 1 ; j <= 5 ; j++) printf("%d ", mmax[i][j]);
//                printf("\n");
//            }
//            printf("\n");
//            for(int i = 1 ; i <= 5 ; i++){
//                for(int j = 1 ; j <= 5 ; j++) printf("%d ", mmin[i][j]);
//                printf("\n");
//            }

        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值