邝斌的ACM模板(伸展树(splay tree))

来源:互联网 发布:用js做一个登录界面 编辑:程序博客网 时间:2024/06/05 16:41

本博客整理自邝斌的ACM模板
3.4、伸展树(splay tree)
题目:维修数列。
经典题,插入、删除、修改、翻转、求和、求和最大的子序列

#define Key_value ch[ch[root][1]][0]const int MAXN = 500010;const int INF = 0x3f3f3f3f;int pre[MAXN],ch[MAXN][2],key[MAXN],size[MAXN];int root,tot1;int sum[MAXN],rev[MAXN],same[MAXN];int lx[MAXN],rx[MAXN],mx[MAXN];int s[MAXN],tot2;//内存池和容量int a[MAXN];int n,q;//debug部分**********************************void Treavel(int x){    if(x)    {        Treavel(ch[x][0]);        printf("结点:%2d: 左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d\n",x,ch[x][0],ch[x][1],pre[x],size[x]);        Treavel(ch[x][1]);    }}void debug(){    printf("root:%d\n",root);    Treavel(root);}//以上是debug部分**************************************void NewNode(int &r,int father,int k){    if(tot2) r = s[tot2--];//取的时候是tot2--,存的时候就是++tot2    else r = ++tot1;    pre[r] = father;    ch[r][0] = ch[r][1] = 0;    key[r] = k;    sum[r] = k;    rev[r] = same[r] = 0;    lx[r] = rx[r] = mx[r] = k;    size[r] = 1;}void Update_Rev(int r){    if(!r)return;    swap(ch[r][0],ch[r][1]);    swap(lx[r],rx[r]);    rev[r] ^= 1;}void Update_Same(int r,int v){    if(!r)return;    key[r] = v;    sum[r] = v*size[r];    lx[r] = rx[r] = mx[r] = max(v,v*size[r]);    same[r] = 1;}void push_up(int r){    int lson = ch[r][0], rson = ch[r][1];    size[r] = size[lson] + size[rson] + 1;    sum[r] = sum[lson] + sum[rson] + key[r];    lx[r] = max(lx[lson],sum[lson] + key[r] + max(0,lx[rson]));    rx[r] = max(rx[rson],sum[rson] + key[r] + max(0,rx[lson]));    mx[r] = max(0,rx[lson]) + key[r] + max(0,lx[rson]);    mx[r] = max(mx[r],max(mx[lson],mx[rson]));}void push_down(int r){    if(same[r])    {        Update_Same(ch[r][0],key[r]);        Update_Same(ch[r][1],key[r]);        same[r] = 0;    }    if(rev[r])    {        Update_Rev(ch[r][0]);        Update_Rev(ch[r][1]);        rev[r] = 0;    }}void Build(int &x,int l,int r,int father){    if(l > r)return;    int mid = (l+r)/2;    NewNode(x,father,a[mid]);    Build(ch[x][0],l,mid-1,x);    Build(ch[x][1],mid+1,r,x);    push_up(x);}void Init(){    root = tot1 = tot2 = 0;    ch[root][0] = ch[root][1] = size[root] = pre[root] = 0;    same[root] = rev[root] = sum[root] = key[root] = 0;    lx[root] = rx[root] = mx[root] = -INF;    NewNode(root,0,-1);    NewNode(ch[root][1],root,-1);    for(int i = 0; i < n; i++)        scanf("%d",&a[i]);    Build(Key_value,0,n-1,ch[root][1]);    push_up(ch[root][1]);    push_up(root);} //旋转,0为左旋,1为右旋void Rotate(int x,int kind){    int y = pre[x];    push_down(y);    push_down(x);    ch[y][!kind] = ch[x][kind];    pre[ch[x][kind]] = y;    if(pre[y])        ch[pre[y]][ch[pre[y]][1]==y] = x;    pre[x] = pre[y];    ch[x][kind] = y;    pre[y] = x;    push_up(y);}//Splay调整,将r结点调整到goal下面void Splay(int r,int goal){    push_down(r);    while(pre[r] != goal)    {        if(pre[pre[r]] == goal)        {            push_down(pre[r]);            push_down(r);            Rotate(r,ch[pre[r]][0] == r);        }        else        {            push_down(pre[pre[r]]);            push_down(pre[r]);            push_down(r);            int y = pre[r];            int kind = ch[pre[y]][0]==y;            if(ch[y][kind] == r)            {                Rotate(r,!kind);                Rotate(r,kind);            }            else            {                Rotate(y,kind);                Rotate(r,kind);            }        }    }    push_up(r);    if(goal == 0) root = r;}int Get_kth(int r,int k){    push_down(r);    int t = size[ch[r][0]] + 1;    if(t == k)return r;    if(t > k)return Get_kth(ch[r][0],k);    else return Get_kth(ch[r][1],k-t);}//在第pos个数后面插入tot个数void Insert(int pos,int tot){    for(int i = 0; i < tot; i++)scanf("%d",&a[i]);    Splay(Get_kth(root,pos+1),0);    Splay(Get_kth(root,pos+2),root);    Build(Key_value,0,tot-1,ch[root][1]);    push_up(ch[root][1]);    push_up(root);}//删除子树void erase(int r){    if(!r)return;    s[++tot2] = r;    erase(ch[r][0]);    erase(ch[r][1]);}//从第pos个数开始连续删除tot个数void Delete(int pos,int tot){    Splay(Get_kth(root,pos),0);    Splay(Get_kth(root,pos+tot+1),root);    erase(Key_value);    pre[Key_value] = 0;    Key_value = 0;    push_up(ch[root][1]);    push_up(root);}//将从第pos个数开始的连续的tot个数修改为cvoid Make_Same(int pos,int tot,int c){    Splay(Get_kth(root,pos),0);    Splay(Get_kth(root,pos+tot+1),root);    Update_Same(Key_value,c);    push_up(ch[root][1]);    push_up(root);}//将第pos个数开始的连续tot个数进行反转void Reverse(int pos,int tot){    Splay(Get_kth(root,pos),0);    Splay(Get_kth(root,pos+tot+1),root);    Update_Rev(Key_value);    push_up(ch[root][1]);    push_up(root);}//得到第pos个数开始的tot个数的和int Get_Sum(int pos,int tot){    Splay(Get_kth(root,pos),0);    Splay(Get_kth(root,pos+tot+1),root);    return sum[Key_value];}//得到第pos个数开始的tot个数中最大的子段和int Get_MaxSum(int pos,int tot){    Splay(Get_kth(root,pos),0);    Splay(Get_kth(root,pos+tot+1),root);    return mx[Key_value];}void InOrder(int r){    if(!r)return;    push_down(r);    InOrder(ch[r][0]);    printf("%d ",key[r]);    InOrder(ch[r][1]);}int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    while(scanf("%d%d",&n,&q) == 2)    {        Init();        char op[20];        int x,y,z;        while(q--)        {            scanf("%s",op);            if(strcmp(op,"INSERT") == 0)            {                scanf("%d%d",&x,&y);                Insert(x,y);            }            else if(strcmp(op,"DELETE") == 0)            {                scanf("%d%d",&x,&y);                Delete(x,y);            }            else if(strcmp(op,"MAKE-SAME") == 0)            {                scanf("%d%d%d",&x,&y,&z);                Make_Same(x,y,z);            }            else if(strcmp(op,"REVERSE") == 0)            {                scanf("%d%d",&x,&y);                Reverse(x,y);            }            else if(strcmp(op,"GET-SUM") == 0)            {                scanf("%d%d",&x,&y);                printf("%d\n",Get_Sum(x,y));            }            else if(strcmp(op,"MAX-SUM") == 0)                     printf("%d\n",Get_MaxSum(1,size[root]-2));        }    }    return 0;}