BZOJ 1500: [NOI2005]维修数列 Splay

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1500

解法:Crash大神的论文上有详细解题方法,实现加调试花了很久很久。然后总算A掉啦。这个题都没过,说

啥学过Splay啊。

///BZOJ 1500

#include <bits/stdc++.h>
using namespace std;
const int inf = 1e9;
const int maxn = 510010;
#define key_val ch[ch[root][1]][0]

int fa[maxn], ch[maxn][2], w[maxn], siz[maxn], sum[maxn], lmax[maxn], rmax[maxn], ans[maxn];
bool rev[maxn];
bool same[maxn];
int a[maxn];
char s[20];
int st[maxn];
int n, m, T, tot, root, top;

int newnode(){
    int num;
    if(top) num=st[top--];
    else num=++tot;
    ch[num][0]=ch[num][1]=fa[num]=0;
    same[num]=rev[num]=0;
    siz[num]=1;
    sum[num]=w[num]=rmax[num]=lmax[num]=-inf;
    return num;
}

void pushup(int x)
{
    if(!x) return;
    siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
    sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+w[x];
    lmax[x]=max(lmax[ch[x][0]], sum[ch[x][0]]+w[x]+max(0,lmax[ch[x][1]]));
    rmax[x]=max(rmax[ch[x][1]], sum[ch[x][1]]+w[x]+max(0,rmax[ch[x][0]]));
    ans[x]=max(max(ans[ch[x][0]],ans[ch[x][1]]), max(0,rmax[ch[x][0]])+w[x]+max(0,lmax[ch[x][1]]));
}

void reverse(int x){
    if(!x) return;
    swap(lmax[x], rmax[x]);
    swap(ch[x][0], ch[x][1]);
    rev[x]^=1;
}

void replace(int x, int d){
    if(!x) return;
    w[x]=d;
    sum[x]=d*siz[x];
    lmax[x]=rmax[x]=ans[x]=max(d,d*siz[x]);
    same[x]=1;
    rev[x]=0;
}

void pushdown(int x){
    if(rev[x]){
        if(ch[x][0]) reverse(ch[x][0]);
        if(ch[x][1]) reverse(ch[x][1]);
        rev[x]=0;
    }
    if(same[x]){
        if(ch[x][0]) replace(ch[x][0], w[x]);
        if(ch[x][1]) replace(ch[x][1], w[x]);
        same[x]=0;
    }
}

void rotate(int x){
    int y = fa[x], kind = ch[y][1] == x;
    pushdown(y), pushdown(x);
    ch[y][kind] = ch[x][!kind];
    fa[ch[y][kind]] = y;
    ch[x][!kind] = y;
    fa[x] = fa[y];
    fa[y] = x;
    ch[fa[x]][ch[fa[x]][1] == y] = x;
    pushup(y), pushup(x);
}

void splay(int x, int goal)
{
    while(fa[x] != goal)
    {
        int y = fa[x], z = fa[y];
        if(z == goal) rotate(x);
        else if((ch[y][1] == x) == (ch[z][1] == y)) rotate(y), rotate(x);
        else rotate(x), rotate(x);
    }
    if(goal == 0) root = x;
}

int find_k(int x, int k){
    pushdown(x);
    if(siz[ch[x][0]]==k-1) return x;
    if(siz[ch[x][0]]>k-1) return find_k(ch[x][0], k);
    else return find_k(ch[x][1], k-siz[ch[x][0]]-1);
}

void build(int l, int r, int rt){
    int mid = (l+r)/2;
    w[rt]=a[mid];
    if(l==r){
        sum[rt]=lmax[rt]=rmax[rt]=ans[rt]=w[rt];
        siz[rt]=1;
        return;
    }
    if(l<mid){
        ch[rt][0]=newnode();
        fa[ch[rt][0]]=rt;
        build(l,mid-1,ch[rt][0]);
    }
    if(mid<r){
        ch[rt][1]=newnode();
        fa[ch[rt][1]]=rt;
        build(mid+1,r,ch[rt][1]);
    }
    pushup(rt);
}

int Query(int l, int num)
{
    int x = find_k(root, l);
    splay(x, 0);
    int y = find_k(ch[x][1], num+1);
    splay(y, x);
    return sum[ch[y][0]];
}

void Insert(int l, int num)
{
    for(int i=1; i<=num; i++) scanf("%d", &a[i]);
    int x = find_k(root, l+1);
    splay(x, 0);
    int y = find_k(ch[x][1], 1);
    splay(y, x);
    ch[y][0] = newnode();
    fa[ch[y][0]] = y;
    build(1, num, ch[y][0]);
    pushup(y);
    pushup(x);
}

void Erase(int x){
    if(!x) return ;
    st[++top]=x;
    if(ch[x][0]) Erase(ch[x][0]);
    if(ch[x][1]) Erase(ch[x][1]);
}

void Delete(int l, int num){
    int x = find_k(root, l);
    splay(x, 0);
    int y = find_k(ch[x][1], num+1);
    splay(y, x);
    Erase(ch[y][0]);
    fa[ch[y][0]]=0;
    ch[y][0]=0;
    pushup(y);
    pushup(x);
}

void Reverse(int l, int num){
    int x = find_k(root, l);
    splay(x, 0);
    int y = find_k(ch[x][1], num+1);
    splay(y, x);
    reverse(ch[y][0]);
    pushup(y);
    pushup(x);
}

void Replace(int l, int num, int d){
    int x = find_k(root, l);
    splay(x, 0);
    int y = find_k(ch[x][1], num+1);
    splay(y, x);
    replace(ch[y][0], d);
    pushup(y);
    pushup(x);
}

int main(){
    lmax[0] = rmax[0] = ans[0] = -inf;
    tot = 2;
    root = 1;
    fa[1] = 0;
    siz[1] = 2;
    ch[1][1] = 2;
    w[1] = sum[1] = lmax[1] = rmax[1] = -inf;
    fa[2] = 1;
    siz[2] = 1;
    w[2] = sum[2] = lmax[2] = rmax[2] = -inf;
    int n, T;
    scanf("%d%d", &n, &T);
    for(int i=1; i<=n; i++) scanf("%d", &a[i]);
    ch[2][0] = newnode(); fa[ch[2][0]] = 2;
    build(1, n, ch[2][0]);
    pushup(2);
    pushup(1);
    while(T--){
        int x, y, z;
        scanf("%s", s);
        if(s[2] == 'X'){
            printf("%d\n", ans[root]);
        }
        if(s[0] == 'G'){
            scanf("%d%d", &x, &y);
            printf("%d\n", Query(x, y));
        }
        if(s[0] == 'I'){
            scanf("%d%d", &x,&y);
            Insert(x, y);
        }
        if(s[0] == 'D'){
            scanf("%d%d", &x,&y);
            Delete(x, y);
        }
        if(s[0] == 'R'){
            scanf("%d%d", &x,&y);
            Reverse(x, y);
        }
        if(s[4] == '-'){
            scanf("%d%d%d", &x,&y,&z);
            Replace(x, y, z);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值