bsoj 2246 【NOI2005】维护数列(splay解法)

【NOI2005】维护数列

Time Limit:20000MS  Memory Limit:200000K
Total Submit:274 Accepted:90

Description

   

Input

   

Output

   

Sample Input

   

Sample Output

   

Hint

    
    
    
   

Source

xinyue

题目:http://mail.bashu.cn:8080/bs_oj/showproblem?problem_id=2246

题意:给你一个数列,每次可能插入一些数,删除一些数,翻转一个区间,询问一个区间的和,还有询问最大的和区间,将一个区间置为相同的一个值。。。

分析:赋值,删除,插入,还有区间和,都比较简单,而翻转和求最大区间和,这个比较麻烦,用到线段树的延迟标记,翻转的话,和赋值差不多,加一个翻转标记,每次下传时,对调两个子节点就行,而最大区间和值,这个需要维护三个值域,一个区间最左开始的最大和,一个区间最右开始的最大和,还有这个区间的最大和。。。

具体自己琢磨下,会更清晰。。。

我的模板貌似慢死了,不加读入优化直接TLE,别人的照样A啊。。。T_T

我得看看他们的代码 ,优化优化^_^

代码:

#include<cstdio>
#include<iostream>
using namespace std;
const int mm=555555;
int a[mm];
int getint()
{
    char ch;
    int flag = 0, tmp = 0;
    for (ch = getchar(); ch < 48 || ch > 57; ch = getchar())
        if (ch == int('-')) break;
    if (ch == int('-')) flag = 1;
    else tmp = int(ch) - 48;
    for (ch = getchar(); 48 <= ch && ch <= 57; ch = getchar())
        tmp = tmp * 10 + int(ch) - 48;
    return (flag) ? -tmp : tmp;
}
struct SplayTree
{
    int son[mm][2],far[mm],num[mm],val[mm],q[mm];
    int sum[mm],lms[mm],rms[mm],ms[mm],dly[mm],w[mm],turn[mm];
    int rt,size,top;
    void Link(int x,int y,int c)
    {
        far[x]=y,son[y][c]=x;
    }
    void Rotate(int x,int c)
    {
        int y=far[x];
        PushDown(y);
        PushDown(x);
        Link(x,far[y],son[far[y]][1]==y);
        Link(son[x][!c],y,c);
        Link(y,x,!c);
        PushUp(y);
    }
    void Splay(int x,int g)
    {
        for(PushDown(x); far[x]!=g;)
        {
            int y=far[x],cx=son[y][1]==x,cy=son[far[y]][1]==y;
            if(far[y]==g)Rotate(x,cx);
            else
            {
                if(cx==cy)Rotate(y,cy);
                else Rotate(x,cx);
                Rotate(x,cy);
            }
        }
        PushUp(x);
        if(!g)rt=x;
    }
    int Select(int k,int g)
    {
        int x=rt;
        PushDown(x);
        while(num[son[x][0]]!=k)
        {
            if(num[son[x][0]]>k)x=son[x][0];
            else k-=num[son[x][0]]+1,x=son[x][1];
            PushDown(x);
        }
        Splay(x,g);
        return x;
    }
    void MemPool(int x)
    {
        if(!x)return;
        q[top++]=x;
        MemPool(son[x][0]);
        MemPool(son[x][1]);
    }
    void NewNode(int y,int &x,int a)
    {
        x=top?q[--top]:++size;
        far[x]=y,val[x]=a,num[x]=1;
        sum[x]=lms[x]=rms[x]=ms[x]=0;
        dly[x]=turn[x]=son[x][0]=son[x][1]=0;
    }
    void Make(int l,int r,int &x,int y)
    {
        if(l>r)return;
        int m=(l+r)>>1;
        NewNode(y,x,a[m]);
        Make(l,m-1,son[x][0],x);
        Make(m+1,r,son[x][1],x);
        PushUp(x);
    }
    void Build(int x,int n)
    {
        for(int i=1; i<=n; ++i)
            a[i]=getint();
        Make(1,n,son[x][0],x);
        Splay(x,0);
    }
    void Prepare(int n)
    {
        ms[0]=lms[0]=rms[0]=-1e9,sum[0]=0;
        NewNode(top=size=0,rt,0);
        NewNode(rt,son[1][1],0);
        num[rt]=2;
        Build(2,n);
    }
    int Interval(int l,int r)
    {
        Select(l,0);
        return Select(r,rt);
    }
    void Insert(int p,int n)
    {
        Build(Interval(p,p+1),n);
    }
    void Delete(int p,int n)
    {
        int x=Interval(p-1,p+n);
        MemPool(son[x][0]);
        son[x][0]=0;
        Splay(x,0);
    }
    void Same(int p,int n,int a)
    {
        int x=Interval(p-1,p+n);
        Change(son[x][0],a);
        Splay(x,0);
    }
    void Reverse(int p,int n)
    {
        int x=Interval(p-1,p+n);
        Turn(son[x][0]);
        Splay(x,0);
    }
    int GetSum(int p,int n)
    {
        int x=Interval(p-1,p+n);
        return sum[son[x][0]];
    }
    int MaxSum()
    {
        return ms[rt];
    }
    void Change(int x,int a)
    {
        if(!x)return;
        dly[x]=1,w[x]=a;
        sum[x]=a*num[x];
        ms[x]=lms[x]=rms[x]=max(sum[x],a);
    }
    void Turn(int x)
    {
        turn[x]^=1;
        swap(lms[x],rms[x]);
    }
    void PushDown(int x)
    {
        if(dly[x])
        {
            val[x]=w[x];
            Change(son[x][0],w[x]);
            Change(son[x][1],w[x]);
            turn[x]=dly[x]=0;
        }
        else if(turn[x])
        {
            swap(son[x][0],son[x][1]);
            Turn(son[x][0]);
            Turn(son[x][1]);
            turn[x]=0;
        }
    }
    void PushUp(int x)
    {
        int a=son[x][0],b=son[x][1];
        num[x]=1+num[a]+num[b];
        sum[x]=val[x]+sum[a]+sum[b];
        ms[x]=max(ms[a],ms[b]);
        lms[x]=lms[a],rms[x]=rms[b];
        if(x>2)
        {
            ms[x]=max(ms[x],val[x]+max(0,rms[a])+max(0,lms[b]));
            lms[x]=max(lms[x],sum[a]+val[x]+max(0,lms[b]));
            rms[x]=max(rms[x],max(0,rms[a])+val[x]+sum[b]);
        }
    }
} spt;
int i,j,k,n,m;
char op[22];
int main()
{
    n=getint(),m=getint();
    spt.Prepare(n);
    while(m--)
    {
        scanf("%s",op);
        if(op[0]!='M')i=getint(),j=getint();;
        if(op[0]=='I')spt.Insert(i,j);
        if(op[0]=='D')spt.Delete(i,j);
        if(op[0]=='M'&&op[2]=='K')
        {
            i=getint(),j=getint(),k=getint();
            spt.Same(i,j,k);
        }
        if(op[0]=='R')spt.Reverse(i,j);
        if(op[0]=='G')printf("%d\n",spt.GetSum(i,j));
        if(op[0]=='M'&&op[2]=='X')printf("%d\n",spt.MaxSum());
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值