P6109 Ynoi2009 rprmq1

P6109 Ynoi2009 rprmq1

二区间合并(猫树)妙妙题。

思路

两维问题,可以离线。

直接线段树空间时间都不允许,考虑将一维离线。

如果分块的话每个块维护块内各个位置的最值,散块暴力处理。

考虑将分块的 O(n) 换成猫树的 O(1)

将第一维加入到猫树上,第二维线段树。

把问题拆分到猫树的区间上。

考虑用线段树处理一次查询,设当前是第 i 列,那么线段树维护第 i 列上每一行的信息(区间最值)。

i 切换到 i+1 时,把在 i+1 做的更改改到线段树上(区间加和,撤销就减掉),i1 同理。

但由于我们每次查询的是 [l,mid] 列的最值信息([mid+1,r] 同理),不能一列都查询一次。

将线段树改造为历史和线段树,支持记录一段时间以来每个区间的最值信息。

mid 列时我们令线段树历史最值等于现最值,移动到 l 查询时区间历史最值就是 [l,mid] 列的最值。

所以线段树要实现这样的功能:

  • 历史最值查询及更新
  • 历史最值同步当前最值

P4314 CPU 监控 有详细介绍,这里不做过多分析。

最后分析复杂度,暴力修改的移动距离在 O(nlogn) 级别且每列平均 约 O(logn) 次,线段树修改时间复杂度 O(mlog2n)

由于猫树,线段树查询时间复杂度 O(qlogn)

总复杂度 O(mlog2n+qlogn)

CODE

#include<bits/stdc++.h>
using namespace std;

#define ll long long

const int maxn=5e5+5;

int n,m,id,cur,q,md;
int a[maxn],pos[maxn];

ll ans[maxn];

int cnt;
struct solder{int l,r,tim;}sr[maxn];
struct option{int l,r,v;};
struct qry{int id,l,r;};

vector<option>chg[maxn];

vector<qry>vec[20][maxn];

namespace linetree
{
    #define lch(p) p*2
    #define rch(p) p*2+1
    struct treenode{ll add,hadd,mx,hmx;bool clrtag;}tr[maxn*8];
    inline void pushup(int p)
    {
        tr[p].mx=max(tr[lch(p)].mx,tr[rch(p)].mx);
        tr[p].hmx=max(tr[lch(p)].hmx,tr[rch(p)].hmx);
    }
    inline void pushdown(int p)
    {
        if(tr[p].clrtag)
        {
            tr[lch(p)].clrtag=tr[rch(p)].clrtag=1;
            tr[lch(p)].hadd=tr[rch(p)].hadd=-1e18;
            tr[lch(p)].hmx=tr[rch(p)].hmx=-1e18;
            tr[p].clrtag=0;
        }
        tr[lch(p)].hadd=max({tr[lch(p)].hadd,tr[lch(p)].add+tr[p].hadd});
        tr[rch(p)].hadd=max({tr[rch(p)].hadd,tr[rch(p)].add+tr[p].hadd});
        tr[lch(p)].hmx=max(tr[lch(p)].hmx,tr[lch(p)].mx+tr[p].hadd);
        tr[rch(p)].hmx=max(tr[rch(p)].hmx,tr[rch(p)].mx+tr[p].hadd);
        tr[lch(p)].mx+=tr[p].add;tr[rch(p)].mx+=tr[p].add;
        tr[lch(p)].add+=tr[p].add;tr[rch(p)].add+=tr[p].add;
        tr[p].add=0,tr[p].hadd=0;
    }
    inline void change(int p,int l,int r,int lx,int rx,int val)
    {
        if(r<lx||l>rx) return ;
        if(lx<=l&&r<=rx)
        {
            tr[p].add+=val;
            tr[p].hadd=max(tr[p].hadd,tr[p].add);
            tr[p].mx+=val;
            tr[p].hmx=max(tr[p].hmx,tr[p].mx);
            return ;
        }
        pushdown(p);
        int mid=(l+r)>>1;
        change(lch(p),l,mid,lx,rx,val);change(rch(p),mid+1,r,lx,rx,val);
        pushup(p);
    }
    inline ll qry(int p,int l,int r,int lx,int rx)
    {
        if(r<lx||l>rx) return -1e18;
        if(lx<=l&&r<=rx) return tr[p].hmx;
        pushdown(p);
        int mid=(l+r)>>1;
        return max(qry(lch(p),l,mid,lx,rx),qry(rch(p),mid+1,r,lx,rx));
    }
    inline void clrtag(){pushdown(1);tr[1].clrtag=1;tr[1].hmx=tr[1].mx;}
}
namespace meowtree
{
    #define lch(p) p*2
    #define rch(p) p*2+1
    inline void build(int p,int l,int r,int dep)
    {
        md=max(md,dep);
        if(l==r){pos[l]=p;return ;}
        int mid=(l+r)>>1;
        build(lch(p),l,mid,dep+1),build(rch(p),mid+1,r,dep+1);
    }
    inline void Go(int mid)
    {
        while(cur<mid)
        {
            cur++;
            for(auto v:chg[cur]) linetree::change(1,1,n,v.l,v.r,v.v);
        }
        while(cur>mid)
        {
            for(auto v:chg[cur]) linetree::change(1,1,n,v.l,v.r,-v.v);
            cur--;
        }
        linetree::clrtag();
    }
    inline void solve(int p,int l,int r,int dep)
    {
        int mid=(l+r)>>1;
        if(l==r)
        {
            Go(mid);
            for(auto v:vec[dep][mid]) ans[v.id]=max(ans[v.id],linetree::qry(1,1,n,v.l,v.r));
            return ;
        }
        Go(mid);
        for(int i=mid;i>=l;i--)
        {
            for(auto v:vec[dep][i]) ans[v.id]=max(ans[v.id],linetree::qry(1,1,n,v.l,v.r));
            for(auto v:chg[cur]) if(-v.v<0) linetree::change(1,1,n,v.l,v.r,-v.v);
            for(auto v:chg[cur]) if(-v.v>0) linetree::change(1,1,n,v.l,v.r,-v.v);
            cur--;
        }

        Go(mid);
        for(int i=mid+1;i<=r;i++)
        {
            cur++;
            for(auto v:chg[cur]) if(v.v<0) linetree::change(1,1,n,v.l,v.r,v.v);
            for(auto v:chg[cur]) if(v.v>0) linetree::change(1,1,n,v.l,v.r,v.v);
            for(auto v:vec[dep][i]) ans[v.id]=max(ans[v.id],linetree::qry(1,1,n,v.l,v.r));
        }
        solve(p*2,l,mid,dep+1),solve(p*2+1,mid+1,r,dep+1);
    }
}

int main()
{
    memset(ans,-0x7f,sizeof(ans));
    scanf("%d%d%d",&n,&m,&q);
    int len=1;while(len<n) len*=2;
    meowtree::build(1,1,len,1);
    for(int i=1;i<=m;i++)
    {
        int lx,rx,ly,ry,x;
        scanf("%d%d%d%d%d",&lx,&ly,&rx,&ry,&x);
        chg[lx].push_back({ly,ry,x});
        chg[rx+1].push_back({ly,ry,-x});
    }
    for(int i=1;i<=q;i++)
    {
        int lx,rx,ly,ry;
        scanf("%d%d%d%d",&lx,&ly,&rx,&ry);
        if(lx==rx){vec[md][lx].push_back({i,ly,ry});continue;}
        int dep=(int)log2(pos[lx])-(int)log2(pos[lx]^pos[rx]);
        vec[dep][lx].push_back({i,ly,ry});
        vec[dep][rx].push_back({i,ly,ry});
    }
    meowtree::solve(1,1,len,1);
    for(int i=1;i<=q;i++) printf("%lld\n",ans[i]);
}

码风优秀,主要部分长度短

posted @   彬彬冰激凌  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示