HDU_4819 二维线段树

13年长春现场赛的G题,赤裸裸的二维线段树,单点更新,区间查询

不过我是第一次写二维的,一开始写T了,原因是我没有好好利用行段,说白一点,还是相当于枚举行,然后对列进行线段树,那要你写二维线段树干嘛

二维就是在每个行段也建一棵树,来代表这个区间的行里的某些列的值

其他操作倒是不难,因为有一维的功底,只是多写一个,刷刷刷就出来了

就是更新操作的时候有点麻烦,up函数不好写,必须先更新底层,复层是区间值,无法先进行更新,然后底层向父层转移也是有点小技巧,因为每个行段点里面的某些列的列端点号肯定是相同的,比如 我dp[1][rt]和dp[2][rt],表示的都是同样的列,只是一个是儿子行,一个是父亲行,父亲行是>儿子行的,所以更新到底层的时候,就往上每次对第一维除2来更新父节点的相关区域即可

还有发现这个不好直接复制,本题是维护最小值和最大值,在建树的时候,直接修改不太好,先把所有的点的最大设置为-inf,最小设置为INF,这样以修改的方式去赋初值,包括之后的修改也是这样。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define INF 1<<30
using namespace std;
const int N = 810;
int ds[N*3][N*3];
int db[N*3][N*3];
int flag[N*3][N*3];
int n;
int A[N][N];
struct node
{
    int mini,maxn;
};
void up(int k,int rt)
{
    db[k][rt]=max(db[k][rt<<1],db[k][rt<<1|1]);
    ds[k][rt]=min(ds[k][rt<<1],ds[k][rt<<1|1]);
    for (int i=(k>>1);i;i>>=1){
        db[i][rt]=max(db[i<<1][rt],db[i<<1|1][rt]);
        ds[i][rt]=min(ds[i<<1][rt],ds[i<<1|1][rt]);
    }
}
void buildc(int k,int rt,int l,int r)
{
    db[k][rt]=-INF;
    ds[k][rt]=INF;
    if (l>=r){
        return;
    }
    int mid=(l+r)>>1;
    buildc(k,lson);
    buildc(k,rson);
}
void buildr(int rt,int l,int r)
{
    buildc(rt,1,1,n);
    if (l>=r){
        return;
    }
    int mid=(l+r)>>1;
    buildr(lson);
    buildr(rson);
}
node queryc(int k,int c1,int c2,int rt,int l,int r)
{
    if (c1<=l && r<=c2){
        node x;
        x.maxn=db[k][rt];
        x.mini=ds[k][rt];
        return x;
    }
    int mid=(l+r)>>1;
    if (mid<c1){
        return queryc(k,c1,c2,rson);
    }
    else
    if (mid>=c2){
        return queryc(k,c1,c2,lson);
    }
    else{
        node a=queryc(k,c1,c2,lson);
        node b=queryc(k,c1,c2,rson);
        node c;
        c.mini=min(a.mini,b.mini);
        c.maxn=max(a.maxn,b.maxn);
        return c;
    }
}
node queryr(int r1,int r2,int c1,int c2,int rt,int l,int r)
{
    if (r1<=l && r<=r2)
    {
        return queryc(rt,c1,c2,1,1,n);
    }
    int mid=(l+r)>>1;
    if (r2<=mid){
        return queryr(r1,r2,c1,c2,lson);
    }
    else
    if (r1>mid){
        return queryr(r1,r2,c1,c2,rson);
    }
    else{
        node a=queryr(r1,r2,c1,c2,lson);
        node b=queryr(r1,r2,c1,c2,rson);
        node c;
        c.maxn=max(a.maxn,b.maxn);
        c.mini=min(a.mini,b.mini);
        return c;
    }
}

void fixc(int val,int k,int C,int rt,int l,int r)
{
    if (l>=r)
    {
        db[k][rt]=val;
        ds[k][rt]=val;
        for (int i=(k>>1);i;i>>=1){
            db[i][rt]=max(db[i<<1][rt],db[i<<1|1][rt]);
            ds[i][rt]=min(ds[i<<1][rt],ds[i<<1|1][rt]);
        }
        return;
    }
    int mid=(l+r)>>1;
    if (C<=mid) fixc(val,k,C,lson);
    else fixc(val,k,C,rson);
    up(k,rt);
}
void fixr(int val,int R,int C,int rt,int l,int r)
{
    if (l>=r)
    {
        fixc(val,rt,C,1,1,n);
        return;
    }
    int mid=(l+r)>>1;
    if (R<=mid) fixr(val,R,C,lson);
    else fixr(val,R,C,rson);
}
int main()
{
    int t,kase=0;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d",&n);
        buildr(1,1,n);
        for (int i=1;i<=n;i++){
            for (int j=1;j<=n;j++){
                scanf("%d",&A[i][j]);
                fixr(A[i][j],i,j,1,1,n);
            }
        }

        int Q,L,R,S;
        scanf("%d",&Q);
        printf("Case #%d:\n",++kase);
        int r1,r2,c1,c2;
        while (Q--)
        {
            scanf("%d%d%d",&L,&R,&S);
            r1=max(L-S/2,1);
            r2=min(L+S/2,n);
            c1=max(R-S/2,1);
            c2=min(R+S/2,n);
            node ans=queryr(r1,r2,c1,c2,1,1,n);
            int ret=(ans.maxn+ans.mini)/2;
            printf("%d\n",ret);
            fixr(ret,L,R,1,1,n);
        }
    }
    return 0;
}

  

HDU_4819 二维线段树

时间: 2024-08-28 13:48:01

HDU_4819 二维线段树的相关文章

HDU1832 二维线段树求最值(模板)

Luck and Love Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 50 Accepted Submission(s): 20   Problem Description 世界上上最远的距离不是相隔天涯海角而是我在你面前可你却不知道我爱你                ―― 张小娴 前段日子,枫冰叶子给Wiskey做了个征婚启事,聘

ZOJ 2859 二维线段树

思路:自己写的第二发二维线段树1A,哈哈,看来对二维的push操作比较了解了:但是还没遇到在两个线段树中同时进行push操作的,其实这题我是想在x维和y维同时进行push操作的,但是想了好久不会,然后看到这题又给出10秒,然后想想在x维线段直接单点查询肯定也过了,然后在第二维就只有pushup操作,在第一维线段树没有pushup操作.要是在第一维也有pushup操作的话,那就不用单点查询那么慢了.不过也A了,想找题即在二维同时进行pushup和pushdown操作的. #include<iost

[POJ2155] Matrix(二维线段树,树套树)

题目链接:http://poj.org/problem?id=2155 题意:给一个01矩阵,两个操作,翻转:子矩阵里每一个数都由0变1,1变0. 查询:查询某一点是0还是1. 一直以为二维线段树就是开一个线段树数组的我- 这题暴力更新每一个小矩形,翻转就+1,最后看看某点的奇偶. 写屎了,特别注意的是在外层查询的时候要先把当前层的内层query掉,接着再向下扩展.这样外层就不用lazy啦 1 #include <algorithm> 2 #include <iostream> 3

poj1195 Mobile phones 二维线段树入门

二维线段树就是树套树,线段树套线段树... #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) #define lson l,m,rt<<1 #

UVA 11297 Census ——二维线段树

[题目分析] 二维线段树模板题目. 简直就是无比的暴力.时间复杂度为两个log. 标记的更新方式比较奇特,空间复杂度为N^2. 模板题目. [代码] #include <cstdio> #include <cstring> //#include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #include <str

tyvj P1716 - 上帝造题的七分钟 二维树状数组区间查询及修改 二维线段树

P1716 - 上帝造题的七分钟 From Riatre    Normal (OI)总时限:50s    内存限制:128MB    代码长度限制:64KB 背景 Background 裸体就意味着身体. 描述 Description “第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵.第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的操作.第三分钟,k说,要能查询,于是便有了求给定矩形区域内的全部数字和的操作.第

POJ 2155 二维线段树

POJ 2155  二维线段树 思路:二维线段树就是每个节点套一棵线段树的树. 刚开始因为题目是求A[I,J],然后在y查询那直接ans^=Map[i][j]的时候没看懂,后面自己把图画出来了才理解. 因为只有0和1,所以可以用异或来搞,而不需要每次都需要修改. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #incl

POJ 2155 二维线段树 经典的记录所有修改再统一遍历 单点查询

本来是想找一个二维线段树涉及懒惰标记的,一看这个题,区间修改,单点查询,以为是懒惰标记,敲到一半发现这二维线段树就不适合懒惰标记,你更新了某段的某列,但其实其他段的相应列也要打标记,但因为区间不一样,又不好打...也可能是我这是在套用一维线段树的思想,还有更好的二维线段树懒惰标记方法 反正到现在我还没搞定二维线段树的懒惰标记,因为这道题不用懒惰标记,因为是二进制序列,区间修改仅限于翻转操作,那就只要记录每次操作,最后查询的时候从上往下把所有修改都来上一遍,就可以了.就类似于树状数组的第二种用法,

【BZOJ4785】[Zjoi2017]树状数组 树套树(二维线段树)

[BZOJ4785][Zjoi2017]树状数组 Description 漆黑的晚上,九条可怜躺在床上辗转反侧.难以入眠的她想起了若干年前她的一次悲惨的OI 比赛经历.那是一道基础的树状数组题.给出一个长度为 n 的数组 A,初始值都为 0,接下来进行 m 次操作,操作有两种: 1 x,表示将 Ax 变成 (Ax + 1) mod 2. 2 l r,表示询问 sigma(Ai) mod 2,L<=i<=r 尽管那个时候的可怜非常的 simple,但是她还是发现这题可以用树状数组做.当时非常yo