【BZOJ】1251: 序列终结者

【题意】给定含有n个0的的数列。

1.区间加值

2.区间翻转

3.区间求最大值

【算法】平衡树(fhq-treap)

需要特别注意的是:

1.使0点对全局无影响并全程保持(例如求max,t[0].mx=-inf)

2.平衡树和线段树的上传区别在于要考虑本身这个点。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100010;
struct tree{int l,r,rnd,num,mx,add,delta,sz;}t[maxn*2];
int st[maxn];
int n,m,root;
void down(int k){
    if(t[k].delta){
        swap(t[k].l,t[k].r);
        if(t[k].l)t[t[k].l].delta^=1;
        if(t[k].r)t[t[k].r].delta^=1;
        t[k].delta=0;
    }
    if(t[k].add){
        int p=t[k].add;
        if(t[k].l)t[t[k].l].add+=p,t[t[k].l].mx+=p,t[t[k].l].num+=p;
        if(t[k].r)t[t[k].r].add+=p,t[t[k].r].mx+=p,t[t[k].r].num+=p;//keep 0->0!!!
        t[k].add=0;
    }
}
int max(int a,int b){return a<b?b:a;}
void up(int k){//different from sgt!
    t[k].mx=max(t[k].num,max(t[t[k].l].mx,t[t[k].r].mx));
    t[k].sz=1+t[t[k].l].sz+t[t[k].r].sz;
}
void dfs(int k){
    if(!k)return;
    dfs(t[k].l);
    dfs(t[k].r);
    up(k);
}
void build(){
    int top=0;
    for(int i=1;i<=n;i++){
        t[i]=(tree){0,0,rand(),0,0,0,0,1};
        while(top&&t[st[top]].rnd>t[i].rnd){
            t[st[top]].r=t[i].l;
            t[i].l=st[top--];
        }
        t[st[top]].r=i;
        st[++top]=i;
    }
    dfs(st[1]);
    t[0].r=0;
    t[0].mx=-0x3f3f3f3f;//make 0 no influence
    root=st[1];
}
int merge(int a,int b){
    if(!a||!b)return a^b;
    if(t[a].rnd<t[b].rnd){
        down(a);
        t[a].r=merge(t[a].r,b);
        up(a);
        return a;
    }
    else{
        down(b);
        t[b].l=merge(a,t[b].l);
        up(b);
        return b;
    }
}
void split(int k,int &l,int &r,int x){
    if(!k)return void(l=r=0);
    down(k);
    if(x<t[t[k].l].sz+1){
        r=k;
        split(t[k].l,l,t[k].l,x);
    }
    else{
        l=k;
        split(t[k].r,t[k].r,r,x-t[t[k].l].sz-1);
    }
    up(k);
}
void plus(int l,int r,int x){
    int a,b,c;
    split(root,b,c,r);
    split(b,a,b,l-1);
    t[b].add+=x;t[b].mx+=x;t[b].num+=x;
    root=merge(a,b);root=merge(root,c);
}
void turn(int l,int r){
    int a,b,c;
    split(root,b,c,r);split(b,a,b,l-1);
    t[b].delta^=1;
    root=merge(a,b);root=merge(root,c);
}
int ask(int l,int r){
    int a,b,c,ans;
    split(root,b,c,r);split(b,a,b,l-1);
    ans=t[b].mx;
    root=merge(a,b);root=merge(root,c);
    return ans;
}
int main(){
    srand(233);
    scanf("%d%d",&n,&m);
    build();
    for(int i=1;i<=m;i++){
        int k,l,r,x;
        scanf("%d%d%d",&k,&l,&r);
        if(l>r)continue;
        if(k==1){
            scanf("%d",&x);
            plus(l,r,x);
        }
        else if(k==2)turn(l,r);
        else printf("%d\n",ask(l,r));
    }
    return 0;
}

时间: 2024-10-11 04:21:11

【BZOJ】1251: 序列终结者的相关文章

伸展树复习 (bzoj 1251 序列终结者)

本来要看LCT的,确发现自己弱得连splay都忘记了,复习一发,顺便重写一发 关键点: 1. 伸展树为左小右大的二叉树,所以旋转操作不会影响树的性质 2. 区间操作为: int u = select(L - 1), v = select(R + 1); splay(u, 0); splay(v, u); //通过旋转操作把询问的区间聚集到根的右子树的左子树下 因为伸展树为左小右大的二叉树,旋转操作后的所以对于闭区间[L, R]之间的所有元素都聚集在根的右子树的左子树下 因为闭区间[L, R],

BZOJ 1251: 序列终结者( splay )

先orz一下clj...我的splay跟着他写的... 这道题很普通的splay我调了这么久 T T , 就是因为 null 的值初始化为0 , 结果就挂了... -------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<iostream>

bzoj 1251: 序列终结者 2011-12-20

1251: 序列终结者Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 650  Solved: 277[Submit][Status][Discuss]Description 网上有许多题,就是给定一个序列,要你支持几种操作:A.B.C.D.一看另一道题,又是一个序列 要支持几种操作:D.C.B.A.尤其是我们这里的某人,出模拟试题,居然还出了一道这样的,真是没技术含量……这样 我也出一道题,我出这一道的目的是为了让大家以后做这种题目有一个“库”可

BZOJ 1251 序列终结者(Splay)

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

Bzoj 1251: 序列终结者 (Splay 模板题)

题面(太裸太裸,不看也罢) 就是维护一个区间加,区间翻转和区间最大值. 贴一个风格以后可以一直用 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define N 100000 6 #define XX getchar() 7 using namespace std; 8 int ch[N][2],fa[N],rev[N],ad[N],b

BZOJ 1251 序列终结者

注意pushup的时候要先判断有没有左右儿子.因为有负数,所以这个可能会出bug. 很烦带标记的数据结构啊...秉承这样一个思路:只要局部的标记下方吗没有问题,整个程序应该都不会怎么出问题. 也就是思路要顺着程序而不是顺着标记. #include<iostream> #include<cstdio> #include<cstring> #define maxn 100500 #define inf 1000000007 using namespace std; int

【BZOJ】1251: 序列终结者(splay)

http://www.lydsy.com/JudgeOnline/problem.php?id=1251 不行..为什么写个splay老是犯逗,这次又是null的mx没有赋值-maxlongint... #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> #inc

BZOJ1251&#183;序列终结者

好像不能附传送门了..这是道sb权限题.. 1251: 序列终结者 Time Limit: 20 Sec  Memory Limit: 162 MB Description 网 上有许多题,就是给定一个序列,要你支持几种操作:A.B.C.D.一看另一道题,又是一个序列 要支持几种操作:D.C.B.A.尤其是我们这里的某人,出模拟试题,居然还出了一道这样的,真是没技术含量……这样 我也出一道题,我出这一道的目的是为了让大家以后做这种题目有一个“库”可以依靠,没有什么其他的意思.这道题目 就叫序列终

【BZOJ】【1251】序列终结者

Splay 还是splay序列维护,这题我WA了的原因是:在Push_up的时候,当前子树的max我是直接取的L.R和v[x]的最大值,但是如果没有左/右儿子,默认是会访问0号结点的mx值,而这个值没有初始化成-INF,所以就会导致所有负max值全部变为0…… 1 /************************************************************** 2 Problem: 1251 3 User: Tunix 4 Language: C++ 5 Resul