bzoj1500(splay)

本文介绍了一道经典的Splay树模板题目,该题目要求实现包括区间求和、最大子段和等在内的六种操作,并提供了详细的代码实现及关键注意事项。

Description
请写一个程序,要求维护一个数列,支持以下 6 种操作:
请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格
这里写图片描述
Input
输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。

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

Sample Input
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
Sample Output
-1
10
1
10
HINT
这里写图片描述


听说是splay模板题,怎么这么不友好QAQ
注意区间修改时标记要提前下传,翻转时也要提前下传!并更新相关的信息
细节比较多,上面这个细节比较关键

#include<bits/stdc++.h>
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define ll long long 
#define ls tr[x].ch[0]
#define rs tr[x].ch[1]
using namespace std;
const int INF = 1000000000;
int root , tot ;
int a[1001000];
struct Splay{
    int ch[2],val,sz,cnt,fa;
    int lmx,rmx,mx,sum,det;
    bool rev;
}tr[1001000];
void read(int &sum){sum = 0;char c = getchar();bool flag = true;while( c < '0' || c > '9' ) {if(c == '-') flag = false;c = getchar();}while( c >= '0' && c <= '9' ) sum = sum * 10 + c - 48 , c = getchar();if(!flag) sum = -sum;}  
queue<int>has;
void update(int x)
{
    if(!x) return;
    tr[x].sz = tr[ls].sz + tr[rs].sz + tr[x].cnt;
    tr[x].lmx = max(tr[ls].lmx,tr[ls].sum + tr[x].val + max(0,tr[rs].lmx));
    tr[x].rmx = max(tr[rs].rmx,tr[rs].sum + tr[x].val + max(0,tr[ls].rmx));
    tr[x].mx = max( max(tr[ls].mx,tr[rs].mx) , max(tr[ls].rmx , 0) + tr[x].val + max(tr[rs].lmx , 0) );
    tr[x].sum = tr[ls].sum + tr[rs].sum + tr[x].val;
}
void zig(int x)
{
    int y = tr[x].fa;int z = tr[y].fa;
    int k = tr[y].ch[1] == x;
    tr[z].ch[tr[z].ch[1] == y] = x; tr[x].fa = z;
    tr[y].ch[k] = tr[x].ch[k^1];    tr[tr[x].ch[k^1]].fa = y;
    tr[x].ch[k^1] = y;              tr[y].fa = x;  
    update(y);update(x);
}
int pick()
{
    int t;
    if(!has.empty()) t = has.front() , has.pop();
    else t = ++tot;
    return t;
}
void reverse(int x)
{
    if(!x) return;
    swap(ls,rs);
    swap(tr[x].lmx,tr[x].rmx);
    tr[x].rev ^= 1;
}
void recover(int x,int v)
{
    if(!x) return;
    tr[x].val = tr[x].det = v;
    tr[x].sum = tr[x].sz *v;
    tr[x].lmx = tr[x].rmx = tr[x].mx = max(v,tr[x].sum);
}
void pushdown(int x)
{
    if(tr[x].rev)
    {
        reverse(ls); 
        reverse(rs);
        tr[x].rev = 0;
    }
    if(tr[x].det != -INF)
    {
        recover(ls,tr[x].det);
        recover(rs,tr[x].det);
        tr[x].det = -INF;
    }
}
void relax(int x,int R)
{
    if(tr[x].fa != R) relax(tr[x].fa , R);
    pushdown(x);
}
void splay(int x,int R)
{
    relax(x,R);
    while(tr[x].fa != R)
    {
        int y = tr[x].fa;int z = tr[y].fa;
        if(z != R)
            (tr[z].ch[1] == y)^(tr[y].ch[1] == x) ? zig(x):zig(y);
        zig(x);
    }
    if(R == 0) root = x;
}
int setup(int x)
{
    int t = pick();
    tr[t].val = a[x];
    tr[t].cnt = 1;
    tr[t].rev = 0;
    tr[t].lmx = tr[t].rmx = tr[t].mx = -INF;
    tr[t].det = -INF;
    return t;
}

int build(int l,int r)
{
    int mid = (l + r)>>1 ,left = 0 , right = 0;
    if(l < mid) left = build(l,mid-1);
    int  x = setup(mid);
    if(r > mid) right = build(mid+1,r);
    if(left) ls = left , tr[left].fa = x;
    else ls = 0;
    if(right) rs = right , tr[right].fa = x;
    else rs = 0;
    update(x);
    return x;
}
int find(int rank)
{
    int x = root;
    while(1)
    {
        pushdown(x);
        if(tr[ls].sz + tr[x].cnt < rank) rank -= tr[ls].sz + tr[x].cnt , x = rs;
        else if(tr[ls].sz >= rank) x = ls;
        else return x; 
    }
}
void recycle(int x)
{
    has.push(x);
    if(ls) recycle(ls);
    if(rs) recycle(rs);
    return;
}
int cas;
char q[15];
int main()
{
    int n , m;
    read(n);read(m);
    tr[0].mx = tr[0].lmx = tr[0].rmx = -INF;
    rep(i,2,n+1) read(a[i]);
    a[1] = a[n+2] = 0;
    root = build(1,n+2);
    rep(i,1,m)
    {
        scanf("%s",q);
        if(q[0] == 'I')
        {
            int rk , num;read(rk);read(num);
            rep(i,1,num) read(a[i]);
            int tmp = build(1,num);
            int x = find(rk+1);splay(x,0);
            int y = find(rk+2);splay(y,x);
            tr[y].ch[0] = tmp;tr[tmp].fa = y;
            update(y);update(x);
        }
        if(q[0] == 'D')
        {
            int rk , num;read(rk);read(num);
            int x = find(rk);splay(x,0);;
            int y = find(rk+num+1);splay(y,x);
            recycle(tr[y].ch[0]);
            tr[y].ch[0] = 0;
            update(y);update(x);
        }
        if(q[0] == 'M' && q[2] == 'K')
        {
            int rk , num;read(rk);read(num);
            int x = find(rk);splay(x,0);
            int y = find(rk+num+1);splay(y,x);
            int c ;read(c);
            recover(tr[y].ch[0],c);
        }
        if(q[0] == 'R')
        {
            int rk , num;read(rk);read(num);
            int x = find(rk);splay(x,0);
            int y = find(rk+num+1);splay(y,x);
            reverse(tr[y].ch[0]);
        }
        if(q[0] == 'G')
        {
            int rk , num;read(rk);read(num);cas++;
            int x = find(rk);splay(x,0);
            int y = find(rk+num+1);splay(y,x);
            printf("%d\n",tr[tr[y].ch[0]].sum);
        }
        if(q[0] == 'M' && q[2] == 'X')
        {
            splay(1,0);splay(n+2,1);
            printf("%d\n",tr[tr[n+2].ch[0]].mx);
        }
    }         
    return 0;
}   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值