bzoj1500: [NOI2005]维修数列

本文分享了一次使用线段树进行区间合并的实际编码经历,详细介绍了如何通过标记辅助实现快速有效的区间操作,并解决了实际中遇到的大内存消耗问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天比较闲所以把这个题拿来练练手。从晚9点写到12点半然后改到凌晨2点终于改完。。。。最后还被大神说是写得快的了 说byvoid大神写了两个早上加一个下午。。。。

前几个操作都很简单之接搞就可以了。对于最后一个操作我们可以用类似于线段树区间合并的标记来做。lmax和rmax,mmax表示左边区间以左开头和以右结尾和中间的最大和。

rever后记得要swap(lmax,rmax)哟,还有要用一个内存池不然会爆内存。。。。。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
#define maxn 1010000
#define INF 0x3f3f3f3f
inline int getint()
{
    int res=0,f=1;char c;
    while(c=getchar(),c<'0'||c>'9'){if(c=='-')f=-1;}
    res=c-'0';
    while(c=getchar(),c>='0'&&c<='9')res=res*10+c-'0';
    return res*f;
}
int tr[maxn][2],fa[maxn],root,n,m;
bool rev[maxn],tag[maxn];
int sum[maxn],lmax[maxn],rmax[maxn],mmax[maxn],v[maxn],a[maxn];
int sta[maxn],top,id[maxn],siz[maxn],cnt;
void pushup(int rt)
{
    int l=tr[rt][0],r=tr[rt][1];
    siz[rt]=siz[l]+siz[r]+1;
    sum[rt]=sum[l]+sum[r]+v[rt];
    lmax[rt]=max(lmax[l],sum[l]+v[rt]+lmax[r]);
    rmax[rt]=max(rmax[r],sum[r]+v[rt]+rmax[l]);
    mmax[rt]=max(mmax[l],mmax[r]);
    mmax[rt]=max(mmax[rt],rmax[l]+v[rt]+lmax[r]);
}
void pushdown(int rt)
{
    int l=tr[rt][0],r=tr[rt][1];
    if(tag[rt])
    {
        tag[rt]=rev[rt]=0;
        if(l)
        {
            tag[l]=1;v[l]=v[rt];
            sum[l]=v[l]*siz[l];
        }
        if(r)
        {
            tag[r]=1;v[r]=v[rt];
            sum[r]=v[r]*siz[r];
        }
        if(v[rt]>=0)
        {
            if(l) mmax[l]=rmax[l]=lmax[l]=sum[l];
            if(r) mmax[r]=rmax[r]=lmax[r]=sum[r];
        }
        else
        {
            if(l) rmax[l]=lmax[l]=0,mmax[l]=v[rt];
            if(r) rmax[r]=lmax[r]=0,mmax[r]=v[rt];
        }
    }
    if(rev[rt])
    {
        rev[rt]^=1;rev[r]^=1;rev[l]^=1;
        swap(lmax[l],rmax[l]);swap(lmax[r],rmax[r]);
        swap(tr[l][0],tr[l][1]);swap(tr[r][0],tr[r][1]);
        //pushup(rt);
    }
}
void rotate(int x,int &rt)
{
    int l,r,z,y;
    y=fa[x];z=fa[y];
    if(x==tr[y][0]) l=0;
    else l=1;r=1^l;
    if(rt==y) rt=x;
    else
    {
        if(tr[z][0]==y) tr[z][0]=x;
        else tr[z][1]=x;
    }
    fa[x]=z;fa[y]=x;fa[tr[x][r]]=y;
    tr[y][l]=tr[x][r];tr[x][r]=y;
    pushup(y);pushup(x);
}
void build(int l,int r,int f)
{
    if(l>r)return;
    int now=id[l],last=id[f];
    if(l==r)
    {
        v[now]=mmax[now]=sum[now]=a[l];
        fa[now]=last;siz[now]=1;
        lmax[now]=rmax[now]=max(0,a[l]);
        if(l<f)tr[last][0]=now;
        else tr[last][1]=now;
        return;
    }
    int mid=(l+r)>>1;now=id[mid];
    build(l,mid-1,mid);build(mid+1,r,mid);
    v[now]=a[mid];fa[now]=last;
    pushup(now);
    if(mid<f)tr[last][0]=now;
    else tr[last][1]=now;
}
void splay(int x,int &rt)
{
    int y,z;
    while(x!=rt)
    {
        y=fa[x];z=fa[y];
        if(y!=rt)
        {
            if((tr[y][0]==x)^(tr[z][0]==y)) rotate(x,rt);
            else rotate(y,rt);
        }
        rotate(x,rt);
    }
}
int select(int now,int rk)
{
    if(rev[now]||tag[now]) pushdown(now);
    int l=tr[now][0],r=tr[now][1];
    int rak=siz[l]+1;
    if(rak==rk) return now;
    if(rak>rk) return select(l,rk);
    else return select(r,rk-rak);
}
void clean(int x)
{
    if(!x)return;
    int l=tr[x][0],r=tr[x][1];
    clean(l);clean(r);
    fa[x]=tr[x][0]=tr[x][1]=0;
    tag[x]=rev[x]=0;
    top++;sta[top]=x;
}
void dele(int s,int b)
{
    int x=select(root,s);
    int y=select(root,s+b+1);
    splay(x,root);splay(y,tr[x][1]);
    clean(tr[y][0]);tr[y][0]=0;
    pushup(y);pushup(x);
}
void query(int s,int b)
{
    int x=select(root,s);
    int y=select(root,s+b+1);
    splay(x,root);splay(y,tr[x][1]);
    printf("%d\n",sum[tr[y][0]]);
}
void solve_rever(int x)
{
    if(tag[x]) return;
    rev[x]^=1;
    swap(tr[x][0],tr[x][1]);
    swap(lmax[x],rmax[x]);
}
void rever(int s,int b)
{
    int x=select(root,s);
    int y=select(root,s+b+1);
    splay(x,root);splay(y,tr[x][1]);
    solve_rever(tr[y][0]);
    pushup(y);pushup(x);
}
void solve_change(int x,int val)
{
    tag[x]=1;v[x]=val;
    sum[x]=siz[x]*v[x];
    if(v[x]>=0)
    {
        mmax[x]=rmax[x]=lmax[x]=sum[x];
    }
    else
    {
        rmax[x]=lmax[x]=0;
        mmax[x]=v[x];
    }
}
void change(int s,int b,int val)
{
    int x=select(root,s);
    int y=select(root,s+b+1);
    splay(x,root);splay(y,tr[x][1]);
    solve_change(tr[y][0],val);
    pushup(y);pushup(x);
}
void ins(int s,int b)
{
    for(int i=1;i<=b;i++)
    {
        a[i]=getint();
        if(top)
        {
            id[i]=sta[top];top--;
        }
        else cnt++,id[i]=cnt;
    }
    build(1,b,0);
    int z=id[(b+1)>>1];
    int x=select(root,s+1);
    int y=select(root,s+2);
    splay(x,root);splay(y,tr[root][1]);
    fa[z]=y;tr[y][0]=z;
    pushup(y);pushup(x);
}
int main()
{
    n=getint();m=getint();
    mmax[0]=-INF;
    a[1]=a[n+2]=-INF;
    for(int i=1;i<=n;i++)
        a[i+1]=getint();
    for(int i=1;i<=n+2;i++)
        id[i]=i;
    build(1,n+2,0);
    root=(n+3)>>1;cnt=n+2;
    char s[10];
    int k,tot,val;
    for(int i=1;i<=m;i++)
    {
        scanf("%s",s);
        if(s[0]=='I')
        {
            k=getint();tot=getint();ins(k,tot);
        }
        if(s[0]=='D')
        {
            k=getint();tot=getint();dele(k,tot);
        }
        if(s[0]=='M')
        {
            if(s[2]=='K')
            {
                k=getint();tot=getint();val=getint();change(k,tot,val);
            }
            else
            {
                printf("%d\n",mmax[root]);
            }
        }
        if(s[0]=='R')
        {
            k=getint();tot=getint();rever(k,tot);
        }
        if(s[0]=='G')
        {
            k=getint();tot=getint();query(k,tot);
        }
    }
    return 0;
}
/*
9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值