1251: 序列终结者(Splay)

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。

Input

第一行两个整数N,M。M为操作个数。 以下M行,每行最多四个整数,依次为K,L,R,V。K表示是第几种操作,如果不是第1种操作则K后面只有两个数。

Output

对于每个第3种操作,给出正确的回答。

Sample Input

4 4

1 1 3 2

1 2 4 -1

2 1 3

3 2 4

Sample Output

2


题解:

  1. 区间加:直接把l,r找到然后打上标记即可
  2. 区间翻转:同上
  3. 区间max:每个点维护一个子树max值即可

又水了一个板子…


AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#include<ext/rope>
using namespace std;
using namespace __gnu_cxx;
typedef long long LL;
const int MAXN = 1e5+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
struct node{
    int son[2],fa,sz,val,mx,lazy,lz;
    inline void init(int f,int v){ fa=f; val=mx=v; sz=1; lazy=lz=0; }
}t[MAXN];
int a[MAXN],root,tot,n,m;
inline int id(int x){ return x==t[t[x].fa].son[1]; }
inline void pushup(int x){
    t[x].sz=t[t[x].son[0]].sz+t[t[x].son[1]].sz+1;
    t[x].mx=t[x].val;
    if(t[x].son[0]) t[x].mx=max(t[x].mx,t[t[x].son[0]].mx);
    if(t[x].son[1]) t[x].mx=max(t[x].mx,t[t[x].son[1]].mx);
}
inline void pushdown(int x){
    if(t[x].lz){
        t[t[x].son[0]].lz+=t[x].lz; t[t[x].son[1]].lz+=t[x].lz;
        t[t[x].son[0]].mx+=t[x].lz; t[t[x].son[1]].mx+=t[x].lz;
        t[t[x].son[0]].val+=t[x].lz; t[t[x].son[1]].val+=t[x].lz;
        t[x].lz=0;
    }
    if(t[x].lazy){
        t[t[x].son[0]].lazy^=1; t[t[x].son[1]].lazy^=1;
        t[x].lazy=0; swap(t[x].son[0],t[x].son[1]);
    }
}
inline void rotate(int x){
    int y=t[x].fa,z=t[y].fa,k=id(x);
    t[z].son[id(y)]=x; t[x].fa=z;
    t[y].son[k]=t[x].son[k^1]; t[t[x].son[k^1]].fa=y;
    t[x].son[k^1]=y; t[y].fa=x;
    pushup(y); pushup(x);
}
inline void splay(int x,int pos){
    while(t[x].fa!=pos){
        int y=t[x].fa,z=t[y].fa;
        if(z!=pos) id(x)==id(y) ? rotate(y):rotate(x);
        rotate(x);
    }
    if(!pos) root=x;
}
inline int build(int rt,int l,int r){
    if(l>r) return 0; int mid=(l+r)>>1;
    int u=++tot;
    t[u].init(rt,a[mid]);
    t[u].son[0]=build(u,l,mid-1); t[u].son[1]=build(u,mid+1,r);
    pushup(u); return u;
}
inline int kth(int x){
    int u=root;
    while(1){
        pushdown(u);
        if(t[t[u].son[0]].sz>=x) u=t[u].son[0];
        else{
            x -= t[t[u].son[0]].sz+1;
            if(!x) return u;
            u=t[u].son[1];
        }
    }
}
signed main(){
#ifndef ONLINE_JUDGE
    freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
#endif // ONLINE_JUDGE
    scanf("%d%d",&n,&m); a[1]=-INF,a[n+2]=INF;
    root = build(0,1,n+2);
    while(m--){
        int op,l,r,v; scanf("%d%d%d",&op,&l,&r);
        int ll=kth(l),rr=kth(r+2);
        splay(ll,0); splay(rr,ll);
        int k=t[t[root].son[1]].son[0];
        if(op==1){
            scanf("%d",&v);
            t[k].mx+=v; t[k].val+=v; t[k].lz+=v;
            pushup(t[root].son[1]); pushup(root);
        }else if(op==2){
            t[k].lazy^=1;
        }else if(op==3){
            printf("%d\n",t[k].mx);
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值