BZOJ 1513 POI2006 Tet-Tetris 3D 二维线段树

题目大意:给定一个矩阵,初始每个位置上的元素都是0,每次选择一个子矩形,将这个子矩形内的值修改为这个子矩形内的最大值+h,求最终所有位置上的最大值

我们需要维护一种数据结构,支持更新子矩形的值和查询子矩形最大值

似乎二维线段树就可以了?

但是YY了一下我们会发现两个没法解决的问题:

1.标记的下传

2.信息的上传

其实。。。

第一个很好办嘛!不下传不就好了!

标记永久化,无需下传,只要查询的时候对线段树路径上的每一个点都询问一遍就行了!

那么第二个呢?

第二个很好办嘛!不上传不就好了!

由于修改只会使元素的值增大,因此区间内只要有任意一个位置被更新过,那么就会对询问的答案产生影响

因此只需要修改的时候对线段树路径上的每一个点都修改一下就好了

于是我们维护两个标记:A标记和B标记

A标记在修改的时候精确覆盖到线段树上的每个对应节点上,查询的时候需要对所有对应节点到根的路径上的所有节点都查询

B标记恰好相反

这样就行了。。。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 1010
using namespace std;

int n,m,q,ans;

struct Segtree{
    Segtree *ls,*rs;
    int val,mark;
    void* operator new (size_t)
    {
        static Segtree *mempool,*C;
        if(C==mempool)
            mempool=(C=new Segtree[1<<15])+(1<<15);
        C->ls=C->rs=0x0;
        C->val=C->mark=0;
        return C++;
    }
    void Update(int val)
    {
        this->val=max(this->val,val);
        mark=max(mark,val);
    }
    void Push_Up()
    {
        val=max(ls->val,rs->val);
    }
    void Push_Down()
    {
        if(!ls) ls=new Segtree;
        if(!rs) rs=new Segtree;
        if(mark)
        {
            ls->Update(mark);
            rs->Update(mark);
            mark=0;
        }
    }
    void Update(int x,int y,int l,int r,int val)
    {
        int mid=x+y>>1;
        if(x==l&&y==r)
        {
            Update(val);
            return ;
        }
        Push_Down();
        if(r<=mid)
            ls->Update(x,mid,l,r,val);
        else if(l>mid)
            rs->Update(mid+1,y,l,r,val);
        else
            ls->Update(x,mid,l,mid,val) , rs->Update(mid+1,y,mid+1,r,val) ;
        Push_Up();
    }
    int Query(int x,int y,int l,int r)
    {
        int mid=x+y>>1;
        if(x==l&&y==r)
            return val;
        Push_Down();
        if(r<=mid)
            return ls->Query(x,mid,l,r);
        if(l>mid)
            return rs->Query(mid+1,y,l,r);
        return max( ls->Query(x,mid,l,mid) , rs->Query(mid+1,y,mid+1,r) );
    }
};

struct abcd{
    abcd *ls,*rs;
    Segtree *A,*B;
    void* operator new (size_t)
    {
        static abcd mempool[M<<1],*C=mempool;
        C->A=new Segtree;
        C->B=new Segtree;
        return C++;
    }
    void Build_Tree(int x,int y)
    {
        int mid=x+y>>1;
        if(x==y)
            return ;
        (ls=new abcd)->Build_Tree(x,mid);
        (rs=new abcd)->Build_Tree(mid+1,y);
    }
    void Update(int x,int y,int l1,int r1,int l2,int r2,int val)
    {
        int mid=x+y>>1;
        B->Update(1,m,l2,r2,val);
        if(x==l1&&y==r1)
        {
            A->Update(1,m,l2,r2,val);
            return ;
        }
        if(r1<=mid)
            ls->Update(x,mid,l1,r1,l2,r2,val);
        else if(l1>mid)
            rs->Update(mid+1,y,l1,r1,l2,r2,val);
        else
            ls->Update(x,mid,l1,mid,l2,r2,val) , rs->Update(mid+1,y,mid+1,r1,l2,r2,val) ;
    }
    int Query(int x,int y,int l1,int r1,int l2,int r2)
    {
        int mid=x+y>>1;
        int re=A->Query(1,m,l2,r2);
        if(x==l1&&y==r1)
            return max(re, B->Query(1,m,l2,r2) );
        if(r1<=mid)
            return max(re, ls->Query(x,mid,l1,r1,l2,r2) );
        if(l1>mid)
            return max(re, rs->Query(mid+1,y,l1,r1,l2,r2) );
        return max(max( ls->Query(x,mid,l1,mid,l2,r2) , rs->Query(mid+1,y,mid+1,r1,l2,r2) ),re);
    }
}*tree=new abcd;

int main()
{
    int i,x1,y1,x2,y2,h;
    cin>>n>>m>>q;
    tree->Build_Tree(1,n);
    for(i=1;i<=q;i++)
    {
        scanf("%d%d%d%d%d",&x2,&y2,&h,&x1,&y1);
        x2+=x1;y2+=y1;x1++;y1++;
        int height=tree->Query(1,n,x1,x2,y1,y2);
        ans=max(ans,height+h);
        tree->Update(1,n,x1,x2,y1,y2,height+h);
    }
    cout<<ans<<endl;
    return 0;
}
时间: 2024-10-05 04:48:12

BZOJ 1513 POI2006 Tet-Tetris 3D 二维线段树的相关文章

BZOJ 1513 POI 2006 Tet-Tetris 3D 二维线段树

题目大意:三维俄罗斯方块,问最后摞了多高. 思路:二维线段树的裸题.但是要注意二维线段树不支持标记下穿.所以就不下传,每次更新答案的时候先看标记,然后用所有的跟标记比较大小之后返回. 具体看代码吧,不知道怎么说. CODE: #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define

【BZOJ1513】【POI2006】Tet-Tetris 3D 二维线段树+标记永久化

题解:题意很裸啊~~~ 培训的时候说要写标记永久化,反正永久化很水,就直接写了. 但是我并不知道为什么要永久化,或者说理解不深刻,但是再遇上肯定能分析出来233. 大概应该可能或许就是: 直接原因:下传标记传不下去. 根本原因: 线段树有两层,这样它的传递可能就有点像拓扑了 就是外层线段树需要往内层线段树传,然后内层线段树还要下传 这样扫到某处时发现,****,还需要顺着两边的标记路径回溯到根, 然后各种压栈啊什么的,才能传下去,而且大概率出错(代码错或思路错). 所以简简单单写个标记永久化好了

【BZOJ1513】[POI2006]Tet-Tetris 3D 二维线段树

[BZOJ1513][POI2006]Tet-Tetris 3D Description Task: Tetris 3D "Tetris" 游戏的作者决定做一个新的游戏, 一个三维的版本, 在里面很多立方体落在平面板,一个立方体开始落下直到碰上一个以前落下的立方体或者落地即停止. 作者想改变一下游戏的目的使得它更大众化,在新游戏中你将知道落下的立方体信息以及位置,你的任务就是回答所有立方体落下后最高的方块的高度.所有的立方体在下落过程中都是垂直的并且不会旋转.平板左下角坐标为原点,并且

BZOJ 2877 NOI2012 魔幻棋盘 二维线段树

题目大意:给定一个矩阵,支持两种操作: 1.将某个子矩阵中的每个值增加一个数 2.询问某个子矩阵中的所有数的GCD 已知所有询问恒过定点(x,y) 算了BZOJ没有原题我还是把原题发上来吧- - <论代码长度与注释长度以及题目简单程度的比例失调关系以及日本饮用水资源的解决方案> <10K+代码是怎样炼成的> <GCD与修改标记的正确用法> <出题人我*你吗系列> <懒惰即美德> 咳咳. 首先我们可以维护一个二维线段树支持子矩阵修改和子矩阵查询 但

[BZOJ4785][ZJOI2017]树状数组(概率+二维线段树)

4785: [Zjoi2017]树状数组 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 297  Solved: 195[Submit][Status][Discuss] Description 漆黑的晚上,九条可怜躺在床上辗转反侧.难以入眠的她想起了若干年前她的一次悲惨的OI 比赛经历.那是一道 基础的树状数组题.给出一个长度为 n 的数组 A,初始值都为 0,接下来进行 m 次操作,操作有两种: 1 x,表示将 Ax 变成 (Ax + 1)

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 #