• 二维线段树->树套树


      现在上真正的二维线段树 毕竟 刚刚那个是卡常 过题我们现在做一个更高级的做法二维线段树。

    大体上维护一颗x轴线段树 然后在每个节点的下方再吊一颗维护y轴的线段树那么此时我们整个平面就被我们玩好了。

    这样形成二维线段树比刚才的要 合理多了。

    写起来 不免有点蒙蔽...然后突然就顿悟了 其实每次我们对于区间的修改大概就是先把x属于x轴的那一段区间给拎出来然后在那个区间之中把那个区间的y轴线段树给修改掉。

    还是刚刚那道题 这次是MLE 了 理论上二维线段树空间复杂度 (MAXN<<2)^2这个复杂度 可是正中下怀的MLE了 开小了一点就可以过了。

    //#include<bits/stdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<ctime> 
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cctype>
    #include<cstdio>
    #include<utility>
    #include<queue>
    #include<stack>
    #include<deque>
    #include<map>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<algorithm>
    #include<cstdlib>
    #define INF 1000000000
    #define ll long long
    #define mx(p) t[p].mx
    #define tag(p) t[p].tag
    #define RE register
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        RE int x=0,f=1;RE char ch=getc();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
        return x*f;
    }
    const int MAXN=3000;
    int n,m,Q;
    int qx,xx,qy,yy,h;
    inline int max(int x,int y){return x>y?x:y;}
    struct wy
    {
        int mx[MAXN],tag[MAXN];
        inline void change(int p,int l,int r,int x,int y,int k)
        {
            mx[p]=max(mx[p],k);
            if(l==x&&r==y)
            {
                tag[p]=max(tag[p],k);
                return;
            }
            int mid=(l+r)>>1;
            if(y<=mid)change(p<<1,l,mid,x,y,k);
            else
            {
                if(x>mid)change(p<<1|1,mid+1,r,x,y,k);
                else change(p<<1,l,mid,x,mid,k),change(p<<1|1,mid+1,r,mid+1,y,k);
            }
        }
        inline int ask(int p,int l,int r,int x,int y)
        {
            if(l==x&&r==y)return mx[p];
            int mid=(l+r)>>1,ans=tag[p];
            if(y<=mid)ans=max(ans,ask(p<<1,l,mid,x,y));
            else
            {
                if(x>mid)ans=max(ans,ask(p<<1|1,mid+1,r,x,y));
                else ans=max(ans,max(ask(p<<1,l,mid,x,mid),ask(p<<1|1,mid+1,r,mid+1,y)));
            }
            return ans;
        }
    };
    struct tx
    {
        wy mx[MAXN],tag[MAXN];
        inline void change(int p,int l,int r,int x,int y,int k)
        {
            mx[p].change(1,1,m,qy,yy,k);
            if(l==x&&r==y)
            {
                tag[p].change(1,1,m,qy,yy,k);
                return;
            }
            int mid=(l+r)>>1;
            if(y<=mid)change(p<<1,l,mid,x,y,k);
            else
            {
                if(x>mid)change(p<<1|1,mid+1,r,x,y,k);
                else change(p<<1,l,mid,x,mid,k),change(p<<1|1,mid+1,r,mid+1,y,k);
            }
        }
        inline int ask(int p,int l,int r,int x,int y)
        {
            if(l==x&&r==y)return mx[p].ask(1,1,m,qy,yy);
            int mid=(l+r)>>1,ans=tag[p].ask(1,1,m,qy,yy);
            if(y<=mid)ans=max(ans,ask(p<<1,l,mid,x,y));
            else
            {
                if(x>mid)ans=max(ans,ask(p<<1|1,mid+1,r,x,y));
                else
                {
                    ans=max(ans,ask(p<<1,l,mid,x,mid));
                    ans=max(ans,ask(p<<1|1,mid+1,r,mid+1,y));
                }
            }
            return ans;
        }
    }T;
    int main()
    {
        freopen("1.in","r",stdin);
        n=read();m=read();Q=read();
        while(Q--)
        {
            xx=read();yy=read();h=read();
            qx=read()+1;qy=read()+1;
            xx=qx+xx-1;yy=qy+yy-1;
            int ans=T.ask(1,1,n,qx,xx);
            T.change(1,1,n,qx,xx,ans+h);
        }
        qx=1;qy=1;xx=n;yy=m;
        printf("%d
    ",T.ask(1,1,n,qx,xx));
        return 0;
    }
    View Code

    操作还是不太熟悉 觉得这个可持久化有点神仙没写过有点 怀疑 不过正确性 和 合理性都是比较显然的。

    简述一下大体的思路吧 首先对x轴开一棵线段树然后 在x轴的这颗线段树每个节点处都吊着一棵y轴的线段树。

    下传修改标记 的时候 对于到过路径上的所有的节点都应该修改值 因为这是标记所致 到了锁定的区间之后标记永久化 对这个tag打上标记 而对内部的y轴线段树也进行一次标记永久化。

    通俗的来说 内外线段树处理方式一模一样。为什么不能下传标记 显然的是我们对于外层线段树的修改 在自己的内部是无法下传的 因为标记是无法合并的 比如说 ta 要修改1 n 1 2这个区间ta又要修改1 n 1 3这个区间显然这两个区间在x线段树上是对等的在y线段树上可并不对等所以这两个标记很难合并 故应该标记永久化减少合并的麻烦。

    这里我们很完美的解决了 二维线段树的问题。 单次操作时间显然是 logn^2.

  • 相关阅读:
    03 java中的基本数据类型和运算符
    02 Eclipse安装
    01 HelloWorld
    express不是内部或外部命令
    win10 内存或系统资源不足,无法打开PPT
    win 10中解决“此文件在另外一个进程中运行”的问题
    后台查找密码暴力破解
    DVWA--全等级暴力破解(Burte Force)
    DVWA简单搭建
    破解版
  • 原文地址:https://www.cnblogs.com/chdy/p/11364344.html
Copyright © 2020-2023  润新知