1. 程式人生 > >BZOJ1500[NOI2005]維修數列——非旋轉treap

BZOJ1500[NOI2005]維修數列——非旋轉treap

char emp height src alt 格式 == bzoj https

題目描述

請寫一個程序,要求維護一個數列,支持以下 6 種操作: 請註意,格式欄 中的下劃線‘ _ ’表示實際輸入文件中的空格 技術分享圖片

輸入

輸入的第1 行包含兩個數N 和M(M ≤20 000),N 表示初始時數列中數的個數,M表示要進行的操作數目。
第2行包含N個數字,描述初始時的數列。
以下M行,每行一條命令,格式參見問題描述中的表格。
任何時刻數列中最多含有500 000個數,數列中任何一個數字均在[-1 000, 1 000]內。
插入的數字總數不超過4 000 000個,輸入文件大小不超過20MBytes。

輸出

對於輸入數據中的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

提示

技術分享圖片

這道題的區間操作十分全,無論是用非旋轉treap還是splay寫,都會有更深入的理解。

講一下每個操作的實現

1、將插入的數再建一棵treap,然後把原treap斷裂,把新建treap合並進去。

2、把treap斷裂成三部分,然後再把左右兩部分合並。

3、也是把treap斷裂成三部分,把中間部分打標記,與線段樹不同的是標記打上就要下傳而不是等到查詢再下傳。

4、和上面一樣,也是斷裂成三部分,中間打標記。

5、斷裂成三部分,輸出中間部分根節點的子樹和。

6、直接輸出根節點的最大連續子段和。

最後不要忘了資源回收(回收節點編號)

最後附上代碼(有註釋)

#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int num;
int pos;
int tot;//樹的大小
int root;//根節點
int n,k,g;
int x,y,z;
int b,c,d;
char ch[5];
queue<int>q;//資源回收隊列
int a[200010];//插入序列及初始序列
int m[500010];//區間最大子段和
int s[500010];//翻轉標記
int f[500010];//修改標記
int r[500010];//隨機數
int ls[500010];//左兒子
int rs[500010];//右兒子
int lm[500010];//子樹區間中從左端點開始的最大連續子段和
int rm[500010];//子樹區間中以右端點結束的最大連續子段和
int val[500010];//節點權值
int sum[500010];//子樹區間和
int size[500010];//子樹大小
int INF=2147483647;
int insert(int v)
{
    int x;
    if(!q.empty())
    {
        x=q.front();
        q.pop();
    }
    else
    {
        x=++tot;
    }
    size[x]=1;
    ls[x]=rs[x]=s[x]=0;
    f[x]=INF;
    r[x]=rand();
    val[x]=sum[x]=v;
    lm[x]=rm[x]=m[x]=v;
    return x;
}
void updata(int x)
{
    if(!x)
    {
        return ;
    }
    size[x]=size[ls[x]]+size[rs[x]]+1;
    sum[x]=sum[ls[x]]+sum[rs[x]]+val[x];
    m[x]=max(max(0,rm[ls[x]])+val[x]+max(0,lm[rs[x]]),max(m[ls[x]],m[rs[x]]));
    lm[x]=max(lm[ls[x]],sum[ls[x]]+val[x]+max(0,lm[rs[x]]));
    rm[x]=max(rm[rs[x]],sum[rs[x]]+val[x]+max(0,rm[ls[x]]));
}
void change(int x,int v)
{
    val[x]=v;
    sum[x]=size[x]*v;
    lm[x]=rm[x]=max(0,sum[x]);
    m[x]=max(val[x],sum[x]);
    f[x]=v;
}
void rotate(int x)
{
    swap(ls[x],rs[x]);
    swap(lm[x],rm[x]);
    s[x]^=1;
}
void downdata(int x)
{
    if(s[x])
    {
        if(ls[x])
        {
            rotate(ls[x]);
        }
        if(rs[x])
        {
            rotate(rs[x]);
        }
    }
    if(f[x]!=INF)
    {
        if(ls[x])
        {
            change(ls[x],f[x]);
        }
        if(rs[x])
        {
            change(rs[x],f[x]);
        }
    }
    s[x]=0;
    f[x]=INF;
}
int build(int l,int r)
{
    if(l>r)
    {
        return 0;
    }
    int mid=(l+r)>>1;
    int v=a[mid];
    int x=insert(v);
    ls[x]=build(l,mid-1);
    rs[x]=build(mid+1,r);
    updata(x);
    return x;
}
void split(int now,int t,int &x,int &y)
{
    if(!now)
    {
        x=y=0;
    }
    else
    {
        downdata(now);
        if(t<=size[ls[now]])
        {
            y=now;
            split(ls[now],t,x,ls[now]);
        }
        else
        {
            x=now;
            split(rs[now],t-size[ls[now]]-1,rs[now],y);
        }
        updata(now);
    }
}
int merge(int x,int y)
{
    if(!x||!y)
    {
        return x+y;
    }
    downdata(x);
    downdata(y);
    if(r[x]<r[y])
    {
        rs[x]=merge(rs[x],y);
        updata(x);
        return x;
    }
    else
    {
        ls[y]=merge(x,ls[y]);
        updata(y);
        return y;
    }
}
void inque(int x)
{
    if(!x)
    {
        return ;
    }
    q.push(x);
    inque(ls[x]);
    inque(rs[x]);
}
int main()
{
    srand(16);
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    val[0]=m[0]=-INF;
    root=build(1,n);
    while(k--)
    {
        scanf("%s",ch);
        if(ch[0]==‘I‘)
        {
            scanf("%d%d",&pos,&num);
            for(int i=1;i<=num;i++)
            {
                scanf("%d",&a[i]);
            }
            z=build(1,num);
            split(root,pos,x,y);
            root=merge(merge(x,z),y);
        }
        else if(ch[0]==‘D‘)
        {
            scanf("%d%d",&pos,&num);
            split(root,pos-1,x,y);
            split(y,num,b,c);
            root=merge(x,c);
            inque(b);
        }
        else if(ch[2]==‘K‘)
        {
            scanf("%d%d%d",&pos,&num,&g);
            split(root,pos-1,x,y);
            split(y,num,b,c);
            change(b,g);
            root=merge(x,merge(b,c));
        }
        else if(ch[0]==‘R‘)
        {
            scanf("%d%d",&pos,&num);
            split(root,pos-1,x,y);
            split(y,num,b,c);
            rotate(b);
            root=merge(x,merge(b,c));
        }
        else if(ch[0]==‘G‘)
        {
            scanf("%d%d",&pos,&num);
            split(root,pos-1,x,y);
            split(y,num,b,c);
            printf("%d\n",sum[b]);
            root=merge(x,merge(b,c));
        }
        else
        {
            printf("%d\n",m[root]);
        }
    }
    return 0;
}

BZOJ1500[NOI2005]維修數列——非旋轉treap