【线段树】牛客 Practice for KD Tree (二维线段树/树套树)

北慕城南 提交于 2020-02-01 02:13:35

Practice for KD Tree

题意:

一个 \(n*n\) 矩阵 \(A\) ,有 \(m_1\) 个操作:给 \(x_1\;x_2\;y_1\;y_2\;w\) ,对所有\(A_{ij}\) (\(i\in[x_1,x_2]\)\(j\in[y_1,y_2]\) )加上 \(w\)
\(m_2\) 个询问:给 \(x_1\;x_2\;y_1\;y_2\) ,求出\(A_{ij}\) (\(i\in[x_1,x_2]\)\(j\in[y_1,y_2]\) )的最大值。

输入:

\(1\)\(3\) 个整数 \(n\;m_1\;m_2\)\(1≤n≤2000,1≤m_1≤5*10^4,1≤m_2≤5*10^5\) );
之后 \(m_1\) 行,每行 \(5\) 个整数:\(x_1\;x_2\;y_1\;y_2\;w\)\(1≤x_1≤x_2≤n,1≤y_1≤y_2≤n,1≤w≤10^9\) );
之后 \(m_2\) 行,每行 \(4\) 个整数:\(x_1\;x_2\;y_1\;y_2\)\(1≤x_1≤x_2≤n,1≤y_1≤y_2≤n\) );

输出:

输出m2行,每行一个整数

官方题解:

n小,所以可以用 \(O(n^2)\)计算出矩阵。然后可以用二维线段树求最值。

个人积累:

【一开始用树状数组求矩阵,明明都是二维差分的思路,我却没想到用二维差分直接 \(O(n^2)\) 求矩阵....
【练习不足o(︶︿︶)o
【然后因为这个树状数组建了四个 \(c[maxn][maxn]\) \(MLE\) ,原本以为线段树 \(tr[maxn<<2][maxn<<2]\) 才可能 \(MLE\) 来着。。结果并不

因为是确定了矩阵A的具体的值,所以线段树无需修改,只需要静态求最值,所以简单多了;
至于二维的建法:以 \(x\) 轴为外部,对每个具体的 \(x_i\),对 \(y\) 轴去建它的子树 \(sg[K].build(1,1,n)\) ;
然后! 当 \(sg[K]\) 每得到一个 \(sg[K].ma[k]\) 时,\(up\) 回去,就是 \(sg[K>>1].ma[k]=max(sg[K>>1].ma[k],sg[K].ma[k])\) ;
这样就建好了!

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e3+5;
const int inf=0x3f3f3f3f;

ll a[maxn][maxn];
int n;
ll ma[maxn<<1][maxn<<1];
struct SG1{
    void up(int K,int k)
    {
        ma[K>>1][k]=max(ma[K>>1][k],ma[K][k]);
        if(K>>1)up(K>>1,k);
    }
    void build(int K,int k,int l,int r,int y)
    {
        if(l==r)
        {
            ma[K][k]=a[l][y];
            up(K,k);
            return;
        }
        int mid=(l+r)>>1;
        build(K,k<<1,l,mid,y);build(K,k<<1|1,mid+1,r,y);
        ma[K][k]=max(ma[K][k<<1],ma[K][k<<1|1]);
        up(K,k);
    }
    ll query(int K,int k,int l,int r,int tl,int tr)
    {
        if(tl<=l&&r<=tr)return ma[K][k];
        int mid=(l+r)>>1;
        ll res=0;
        if(tl<=mid)res=query(K,k<<1,l,mid,tl,tr);
        if(tr>mid&&res<ma[K][k<<1|1])res=max(res,query(K,k<<1|1,mid+1,r,tl,tr));
        return res;
    }
}sg;
inline void build(int k,int l,int r)
{
    if(l==r)
    {
        sg.build(k,1,1,n,l);
        return;
    }
    int mid=(l+r)>>1;
    build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
inline ll query(int k,int l,int r,int x1,int y1,int x2,int y2)
{
    if(y1<=l&&r<=y2)return sg.query(k,1,1,n,x1,x2);
    int mid=(l+r)>>1;
    ll res=0;
    if(y1<=mid)res=query(k<<1,l,mid,x1,y1,x2,y2);
    if(y2>mid&&res<ma[k<<1|1][1])res=max(res,query(k<<1|1,mid+1,r,x1,y1,x2,y2));
    return res;
}
int main()
{
    int m1,m2,x1,y1,x2,y2,w;
    scanf("%d%d%d",&n,&m1,&m2);
    while(m1--)
    {
        scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&w);
        a[x1][y1]+=w;a[x2+1][y2+1]+=w;
        a[x1][y2+1]-=w;a[x2+1][y1]-=w;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
    build(1,1,n);
    while(m2--)
    {
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        printf("%lld\n",query(1,1,n,x1,y1,x2,y2));
    }
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!