NKOJ 3884 (NOI 2005) 维修数列(Splay)

P3884 NOI2005维修数列

问题描述

这里写图片描述

输入格式

第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。

输出格式

对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。

样例输入

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

样例输出

-1
10
1
10

提示

你可以认为在任何时刻,数列中至少有 1 个数。 输入数据一定是正确的,即指定位置的数在数列中一定存在。

50%的数据中,任何时刻数列中最多含有 30 000 个数; 100%的数据中,任何时刻数列中最多含有 500 000 个数。

100%的数据中,任何时刻数列中任何一个数字均在[-1 000, 1 000]内。 100%的数据中,M ≤20 000,插入的数字总数不超过 4 000 000 个,输入文件 大小不超过 20MBytes。


Splay模板题,修改和翻转用lazy,维护区间和,考虑如何维护最大区间和,用类似线段树的方法解决即可。
注意当儿子为0时要特别小心。


代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#define N 8000005
#define max(a,b) ((a>b)?(a):(b))
using namespace std;
const int Inf=99999999;
int n,m,A[N],L,R;
int tot,rt,ls[N],rs[N],fa[N],si[N],v[N],lazy1[N],lazy2[N],lmax[N],rmax[N],Max[N],sum[N];
int GM(int x,int y,int z)
{
    if(x>=y&&x>=z)return x;
    if(y>=z)return y;
    return z;
}
void MT(int p)
{
    lmax[p]=GM(lmax[ls[p]],sum[ls[p]]+v[p],sum[ls[p]]+v[p]+lmax[rs[p]]);
    rmax[p]=GM(rmax[rs[p]],sum[rs[p]]+v[p],sum[rs[p]]+v[p]+rmax[ls[p]]);
    Max[p]=GM(Max[ls[p]],Max[rs[p]],max(0,lmax[rs[p]])+max(0,rmax[ls[p]])+v[p]);
    sum[p]=sum[ls[p]]+sum[rs[p]]+v[p];
    si[p]=si[ls[p]]+si[rs[p]]+1;
}
void PD(int p)
{
    if(lazy1[p])
    {
        swap(ls[ls[p]],rs[ls[p]]);
        swap(lmax[ls[p]],rmax[ls[p]]);
        swap(ls[rs[p]],rs[rs[p]]);
        swap(lmax[rs[p]],rmax[rs[p]]);
        lazy1[ls[p]]^=1;
        lazy1[rs[p]]^=1;
    }
    if(lazy2[p]!=Inf)
    {
        v[ls[p]]=v[rs[p]]=lazy2[p];
        sum[ls[p]]=lazy2[p]*si[ls[p]];
        sum[rs[p]]=lazy2[p]*si[rs[p]];
        lmax[ls[p]]=rmax[ls[p]]=Max[ls[p]]=lazy2[p]>0?lazy2[p]*si[ls[p]]:lazy2[p];
        lmax[rs[p]]=rmax[rs[p]]=Max[rs[p]]=lazy2[p]>0?lazy2[p]*si[rs[p]]:lazy2[p];
        lazy2[ls[p]]=lazy2[rs[p]]=lazy2[p];
    }
    lazy1[p]=0;lazy2[p]=Inf;
}
void Zig(int x)
{
    int y=fa[x],z=fa[y];
    if(y==ls[z])ls[z]=x;else rs[z]=x;fa[x]=z;
    ls[y]=rs[x];fa[rs[x]]=y;
    rs[x]=y;fa[y]=x;
    MT(y);MT(x);
}
void Zag(int x)
{
    int y=fa[x],z=fa[y];
    if(y==ls[z])ls[z]=x;else rs[z]=x;fa[x]=z;
    rs[y]=ls[x];fa[ls[x]]=y;
    ls[x]=y;fa[y]=x;
    MT(y);MT(x);
}
void Splay(int x,int t)
{
    int y,z;
    while(fa[x]!=t)
    {
        y=fa[x];z=fa[y];
        if(z)PD(z);
        if(y)PD(y);
        if(x)PD(x);
        if(z!=t)
        {
            if(y==ls[z])
            {
                if(x==ls[y])Zig(y),Zig(x);
                else Zag(x),Zig(x);
            }
            else
            {
                if(x==rs[y])Zag(y),Zag(x);
                else Zig(x),Zag(x);
            }
        }
        else if(x==ls[y])Zig(x);else Zag(x);
    }
    if(!t)rt=x;
}
int BT(int x,int y)
{
    if(x>y)return 0;
    int p=++tot;
    lazy2[p]=Inf;
    if(x==y&&x==0)L=p;
    if(x==y&&x==n+1)R=p;
    if(x<y)
    {
        int mid=x+y>>1;
        if(mid==0)L=p;
        if(mid==n+1)R=p;
        v[p]=A[mid];
        ls[p]=BT(x,mid-1);
        rs[p]=BT(mid+1,y);
        fa[ls[p]]=p;
        fa[rs[p]]=p;
        MT(p);
    }
    else v[p]=sum[p]=lmax[p]=rmax[p]=Max[p]=A[x],si[p]=1;
    return p;
}
int Find(int k)
{
    int p=rt;
    while(p)
    {
        PD(p);
        if(si[ls[p]]+1==k)return p;
        if(si[ls[p]]>=k)p=ls[p];
        else k-=si[ls[p]]+1,p=rs[p];
    }
    return p;
}
void INS()
{
    int i,x,y,a,b;
    scanf("%d%d",&x,&y);
    for(i=1;i<=y;i++)scanf("%d",&A[i]);
    a=Find(x+1);b=Find(x+2);
    Splay(a,0);Splay(b,rt);
    tot++;
    v[tot]=sum[tot]=lmax[tot]=rmax[tot]=Max[tot]=A[1];
    lazy2[tot]=Inf;si[tot]=1;
    for(i=2;i<=y;i++)
    {
        tot++;
        v[tot]=A[i];
        lazy2[tot]=Inf;
        ls[tot]=tot-1;
        fa[tot-1]=tot;
        MT(tot);
    }
    fa[tot]=b;ls[b]=tot;MT(b);MT(a);
}
void DEL()
{
    int x,y,a,b;
    scanf("%d%d",&x,&y);
    a=Find(x);b=Find(x+y+1);
    Splay(a,0);Splay(b,rt);
    fa[ls[rs[rt]]]=0;
    ls[rs[rt]]=0;
    MT(rs[rt]);
    MT(rt);
}
void CHA()
{
    int x,y,z,a,b,p;
    scanf("%d%d%d",&x,&y,&z);
    a=Find(x);b=Find(x+y+1);
    Splay(a,0);Splay(b,rt);
    p=ls[rs[rt]];
    lazy2[p]=z;
    v[p]=z;sum[p]=z*si[p];
    lmax[p]=rmax[p]=Max[p]=z>0?z*si[p]:z;
    MT(rs[rt]);
    MT(rt);
}
void REV()
{
    int x,y,a,b,p;
    scanf("%d%d",&x,&y);
    a=Find(x);b=Find(x+y+1);
    Splay(a,0);Splay(b,rt);
    p=ls[rs[rt]];
    lazy1[p]^=1;
    swap(ls[p],rs[p]);
    swap(lmax[p],rmax[p]);
    MT(rs[rt]);
    MT(rt);
}
void SUM()
{
    int x,y,a,b;
    scanf("%d%d",&x,&y);
    a=Find(x);b=Find(x+y+1);
    Splay(a,0);Splay(b,rt);
    printf("%d\n",sum[ls[rs[rt]]]);
}
void MAX()
{
    Splay(L,0);Splay(R,rt);
    printf("%d\n",Max[ls[rs[rt]]]);
}
int main()
{
    int i,x,y,z;char s[15];
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)scanf("%d",&A[i]);
    rt=BT(0,n+1);
    while(m--)
    {
        scanf("%s",s);
        if(s[2]=='S')INS();
        if(s[2]=='L')DEL();
        if(s[2]=='K')CHA();
        if(s[2]=='V')REV();
        if(s[2]=='T')SUM();
        if(s[2]=='X')MAX();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值