bzoj1251 序列终结者 splay

15 篇文章 0 订阅

Description


网上有许多题,就是给定一个序列,要你支持几种操作:A、B、C、D。一看另一道题,又是一个序列 要支持几种操作:D、C、B、A。尤其是我们这里的某人,出模拟试题,居然还出了一道这样的,真是没技术含量……这样 我也出一道题,我出这一道的目的是为了让大家以后做这种题目有一个“库”可以依靠,没有什么其他的意思。这道题目 就叫序列终结者吧。 给定一个长度为N的序列,每个序列的元素是一个整数(废话)。要支持以下三种操作: 1. 将[L,R]这个区间内的所有数加上V。 2. 将[L,R]这个区间翻转,比如1 2 3 4变成4 3 2 1。 3. 求[L,R]这个区间中的最大值。 最开始所有元素都是0。

N<=50000,M<=100000。

Solution


又sb了,裸的splay调半天。每个人的splay写法都不太一样,这种模板果然还是要自己熟悉
这里用类似线段树的写法建树,两个tag注意push的顺序即可。那一段膜标膜来的remove操作没有什么卵用,实际上tag已经在旋转的时候传掉了。仔细一想这应该是写法的问题,大概我的写法比较优秀

Code


#include <stdio.h>
#include <algorithm>
#include <stack>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
const int INF=0x7fffffff;
const int N=500005;
std:: stack<int> stack;
int son[N][2],lazy[N][2],fa[N];
int size[N],mx[N],a[N],root;
int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}
void push_up(int now) {
    mx[now]=std:: max(a[now],std:: max(mx[son[now][0]],mx[son[now][1]]));
    size[now]=size[son[now][0]]+size[son[now][1]]+1;
}
void push_down(int now) {
    if (lazy[now][1]) {
        if (son[now][0]) {
            lazy[son[now][0]][1]+=lazy[now][1];
            mx[son[now][0]]+=lazy[now][1];
            a[son[now][0]]+=lazy[now][1];
        }
        if (son[now][1]) {
            lazy[son[now][1]][1]+=lazy[now][1];
            mx[son[now][1]]+=lazy[now][1];
            a[son[now][1]]+=lazy[now][1];
        }
        lazy[now][1]=0;
    }
    if (lazy[now][0]) {
        std:: swap(son[now][0],son[now][1]);
        lazy[son[now][0]][0]^=1;
        lazy[son[now][1]][0]^=1;
        lazy[now][0]^=1;
    }
}
void rotate(int x) {
    int y=fa[x]; int z=fa[y];
    int k=son[y][1]==x;
    son[z][son[z][1]==y]=x;
    fa[x]=z;
    son[y][k]=son[x][!k];
    fa[son[x][!k]]=y;
    son[x][!k]=y;
    fa[y]=x;
    push_up(y); push_up(x);
}
/*void remove(int x,int y) {
    while (x!=y) {
        stack.push(x);
        x=fa[x];
    }
    stack.push(y);
    while (!stack.empty()) {
        push_down(stack.top());
        stack.pop();
    }
}*/
void splay(int x,int goal=0) {
    // remove(x,goal);
    while (fa[x]!=goal) {
        int y=fa[x]; int z=fa[y];
        if (z!=goal) {
            if ((son[z][1]==y)^(son[y][1]==x)) rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
    if (!goal) root=x;
}
int buildTree(int l,int r) {
    int mid=(l+r)>>1;
    size[mid]=1; mx[mid]=a[mid];
    if (l==r) return mid;
    if (l<mid) {
        son[mid][0]=buildTree(l,mid-1);
        fa[son[mid][0]]=mid;
    }
    if (mid<r) {
        son[mid][1]=buildTree(mid+1,r);
        fa[son[mid][1]]=mid;
    }
    push_up(mid);
    return mid;
}
int find(int k) {
    int now=root;
    while (233) {
        push_down(now);
        if (size[son[now][0]]+1==k) return now;
        else if (size[son[now][0]]+1<k) {
            k-=size[son[now][0]]+1;
            now=son[now][1];
        } else now=son[now][0];
    }
}
void operate(int &l,int &r) {
    l=find(l); splay(l);
    r=find(r+2); splay(r,l);
}
void reverse(int l,int r) {
    operate(l,r);
    lazy[son[r][0]][0]^=1;
}
void modify(int l,int r,int v) {
    operate(l,r);
    lazy[son[r][0]][1]+=v;
    mx[son[r][0]]+=v;
    a[son[r][0]]+=v;
}
int query(int l,int r) {
    operate(l,r);
    return mx[son[r][0]];
}
int main(void) {
    int n=read(),m=read();
    a[1]=a[n+2]=mx[0]=-INF;
    root=buildTree(1,n+2);
    while (m--) {
        int opt=read(),l=read(),r=read();
        if (opt==1) {
            int v=read();
            modify(l,r,v);
        } else if (opt==2) {
            reverse(l,r);
        } else if (opt==3) {
            printf("%d\n", query(l,r));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值