HNOI 2000 Splay Tree 模版题目

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

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

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;
#define M 500010
#define inf 1<<30
#define keytree (c[c[root][1]][0])
//变量定义,根据题意而定。
int p[M],c[M][2],s[M],v[M],rev[M],same[M];
int Lmax[M],Rmax[M],Max[M],d[M],sum[M];
int root,n,m,len,top1,top2,sta[M],que[M];
//根据左右子树来更新父亲。。
inline void push_up(int x)
{
    if(!x) return;
    int l=c[x][0],r=c[x][1];
    s[x]=1+s[l]+s[r];
    sum[x]=v[x]+sum[l]+sum[r];
    Lmax[x]=max(Lmax[l],sum[l]+v[x]+max(0,Lmax[r]));
    Rmax[x]=max(Rmax[r],sum[r]+v[x]+max(0,Rmax[l]));
    Max[x]=max(Lmax[r],0)+v[x]+max(Rmax[c[x][0]],0);
    Max[x]=max(Max[x],max(Max[l],Max[r]));
}
//反转更新。。
inline void Date_rev(int x)
{
    if(!x) return;
    swap(c[x][0],c[x][1]);
    swap(Lmax[x],Rmax[x]);
    rev[x]^=1;
}
//区间更新成同一个值。。
inline void Date_same(int x,int val)
{
    if(!x) return;
    v[x]=val,sum[x]=s[x]*val;
    Lmax[x]=Rmax[x]=Max[x]=max(v[x],sum[x]);
    same[x]=1;
}
//lazy操作,更新当前需要更新的。。
inline void push_down(int x)
{
    if(!x) return;
    if(rev[x])
    {
        Date_rev(c[x][0]);
        Date_rev(c[x][1]);
    }
    if(same[x])
    {
        Date_same(c[x][0],v[x]);
        Date_same(c[x][1],v[x]);
    }
    rev[x]=same[x]=0;
}
//开辟节点,通常为固定模式,改变的仅仅为部分变量。。
inline void newnode(int &x,int val)
{
    if(top2) x=sta[top2--];
    else x=++top1;
    s[x]=1;
    p[x]=c[x][0]=c[x][1]=same[x]=rev[x]=0;
    v[x]=Lmax[x]=Rmax[x]=Max[x]=sum[x]=val;
}
//建树插入节点。。
inline void build(int &x,int l,int r,int pre)
{
    if(l>r) return;
    int mid=(l+r)>>1;
    newnode(x,d[mid]);
    build(c[x][0],l,mid-1,x);
    build(c[x][1],mid+1,r,x);
    p[x]=pre,push_up(x);
}
//初始话,基本上固定,改变的仅仅是部分变量。。
inline void Splay_init()
{
    root=top1=top2=same[0]=rev[0]=sum[0]=0;
    p[0]=c[0][0]=c[0][1]=s[0]=v[0]=0;
    Lmax[0]=Rmax[0]=Max[0]=-1001;
    newnode(root,-inf);
    newnode(c[root][1],-inf);
    p[top1]=root,s[root]=2;
    build(keytree,1,n,c[root][1]);
    push_up(c[root][1]);
    push_up(root);
}
//旋转函数,内容基本固定。。
inline void Rotate(int x,int f)
{
    int y=p[x];
    push_down(y),push_down(x);
    c[y][!f]=c[x][f];
    p[c[x][f]]=y;
    p[x]=p[y];
    if(p[x]) c[p[y]][c[p[y]][1]==y]=x;
    p[y]=x,c[x][f]=y;
    push_up(y);
}
//伸展函数,内容基本固定。。
inline void Splay(int x,int goal)
{
    while(p[x]!=goal)
    {
        if(p[p[x]]==goal) Rotate(x,c[p[x]][0]==x);
        else
        {
            int y=p[x],f=c[p[y]][0]==y;
            if(c[y][f]==x) Rotate(x,!f);
            else Rotate(y,f);
            Rotate(x,f);
        }
    }
    push_up(x);
    if(!goal) root=x;
}
//查找第k个元素,内容基本固定。。
inline void RotateTo(int k,int goal)
{
    int x=root;
    push_down(x);
    while(s[c[x][0]]!=k)
    {
        if(s[c[x][0]]>k) x=c[x][0];
        else k-=s[c[x][0]]+1,x=c[x][1];
        push_down(x);
    }
    Splay(x,goal);
}
//删除以x节点为祖先的子树,回收内存。
//通常为题目数据较大是应用。。。
inline void erase(int x)
{
    int head=1,rear=1;
    que[head]= x;
    while(head<=rear)
    {
        sta[++top2]=que[head];
        if(c[que[head]][0]) que[++rear]=c[que[head]][0];
        if(c[que[head]][1]) que[++rear]=c[que[head]][1];
        head++;
    }
}
//插入操作,通常也为固定内容。。
inline void Insert(int id)
{
    RotateTo(id,0);
    RotateTo(id+1,root);
    build(keytree,1,len,c[root][1]);
    push_up(c[root][1]),push_up(root);
}
//删除函数,通常为固定内容。。
inline void Delete(int id,int num)
{
    RotateTo(id-1,0);
    RotateTo(id+num,root);
    erase(keytree); //此处如果题目数据不大可以省略。。
    c[c[root][1]][0]=0;
    push_up(c[root][1]),push_up(root);
}
//区间操作函数。。
inline void Same(int id,int num,int val)
{
    RotateTo(id-1,0);
    RotateTo(id+num,root);
    Date_same(keytree,val);
}
//滚动
inline void revolve(int l,int r,int num)
   {
    num%=(r-l+1);
    num=(num+(r-l+1))%(r-l+1);
    if(!num) return;
    RotateTo(r-num,0);
    RotateTo(r+1,root);
    int x=keyTree;
    keyTree=0;
    push_up(ch[root][1]);
    push_up(root);
    RotateTo(l-1,0);
    RotateTo(l,root);
    keyTree=x;
    pre[keyTree]=ch[root][1];
    push_up(ch[root][1]);
    push_up(root);
}
//反转函数。。
inline void Reverse(int id,int num)
{
    RotateTo(id-1,0);
    RotateTo(id+num,root);
    Date_rev(keytree);
}
inline void Getsum(int id,int num)
{
    RotateTo(id-1,0);
    RotateTo(id+num,root);
    printf("%d\n",sum[keytree]);
}
inline void Max_sum()
{
    RotateTo(0,0);
    RotateTo(s[root]-1,root);
    printf("%d\n",Max[keytree]);
}
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;
}
int main()
{
    char str[20];
    int i,aa,bb,cc;
     n=getint(),m=getint();
    for(i=1;i<=n;i++) d[i]=getint();
    Splay_init();
    while(m--)
    {
        scanf("%s",str);
        if(str[0]=='I')
        {
           aa=getint(),len=getint();
            for(i=1;i<=len;i++) d[i]=getint();
            Insert(aa);
        }
        else if(str[0]=='D') aa=getint(),bb=getint(),Delete(aa,bb);
        else if(str[0]=='R') aa=getint(),bb=getint(),Reverse(aa,bb);
        else if(str[0]=='M'&&str[2]=='K')
            aa=getint(),bb=getint(),cc=getint(),Same(aa,bb,cc);
        else if(str[0]=='G') aa=getint(),bb=getint(),Getsum(aa,bb);
        else Max_sum();
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值