bzoj 1251 序列终结者

1251: 序列终结者

Time Limit: 20 Sec Memory Limit: 162 MB
Submit: 4170 Solved: 1752
[Submit][Status][Discuss]
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

【数据范围】

N<=50000,M<=100000。


【分析】
水题…大题的子问题…更新了一种区间翻转的pushdown写法,感觉这样比较清爽吧…
(ch数组开成ch[mxn][0]也是没谁了…为啥不提示我RE呢)


【代码】

//bzoj 序列终结者 
#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=100005;
int n,m,root,sz;
int a[mxn],f[mxn],key[mxn],mx[mxn],size[mxn],ch[mxn][2],add[mxn],mark[mxn];
inline int get(int x)
{
    if(ch[f[x]][1]==x) return 1;return 0;
}
inline void update(int x)
{
    if(!x) return;
    size[x]=1;
    if(ch[x][0]) size[x]+=size[ch[x][0]];
    if(ch[x][1]) size[x]+=size[ch[x][1]];
    mx[x]=key[x];
    if(ch[x][0]) mx[x]=max(mx[x],mx[ch[x][0]]);
    if(ch[x][1]) mx[x]=max(mx[x],mx[ch[x][1]]);
}
inline void ADD(int now,int w)
{
    if(!now) return;
    key[now]+=w,mx[now]+=w,add[now]+=w;
}
inline void reverse(int now)
{
    if(!now) return;
    swap(ch[now][0],ch[now][1]);
    mark[now]^=1;
}
inline void pushdown(int now)
{
    if(!now) return;
    int l=ch[now][0],r=ch[now][1];
    if(add[now])
    {
        if(l) ADD(l,add[now]);
        if(r) ADD(r,add[now]);
        add[now]=0;
    } 
    if(mark[now])
    {
        if(l) reverse(l);
        if(r) reverse(r);
        mark[now]=0;
    }
}
inline void rotate(int now)
{
    if(!now) return;
    pushdown(now);
    int fa=f[now],fafa=f[fa],which=get(now);
    ch[fa][which]=ch[now][which^1],f[ch[fa][which]]=fa;
    ch[now][which^1]=fa,f[fa]=now;
    f[now]=fafa;
    if(fafa) ch[fafa][ch[fafa][1]==fa]=now;
    update(fa),update(now);
}
inline void splay(int x,int lastfa)
{
    for(int fa;(fa=f[x])!=lastfa;rotate(x))
      if(f[fa]!=lastfa) rotate(get(x)==get(fa)?fa:x);
    if(!lastfa) root=x;
}
inline int number(int x)
{
    int now=root;
    while(1)
    {
        pushdown(now);
        if(ch[now][0] && x<=size[ch[now][0]]) now=ch[now][0];
        else
        {
            if(x==size[ch[now][0]]+1) return now;
            x=x-size[ch[now][0]]-1;
            now=ch[now][1];pushdown(now);
        }
    }
}
inline int build(int fa,int l,int r)
{
    if(l>r) return 0;
    int now=++sz,mid=(l+r)>>1;
    f[now]=fa,size[now]=1;
    ch[now][0]=build(now,l,mid-1);
    ch[now][1]=build(now,mid+1,r);
    update(now);
    return now;
}
int main()
{
    int i,j,opt,x,y,z,w;
    scanf("%d%d",&n,&m);
    root=build(0,1,n+2);
    while(m--)
    {
        scanf("%d",&opt);
        if(opt==1)  //区间加 
        {
            scanf("%d%d%d",&x,&y,&w);
            x++,y++;
            x=number(x-1),y=number(y+1);
            splay(x,0),splay(y,x);
            ADD(ch[y][0],w);
        }
        if(opt==2)  //区间翻转
        {
            scanf("%d%d",&x,&y);
            x++,y++;
            x=number(x-1),y=number(y+1);
            splay(x,0),splay(y,x);
            reverse(ch[y][0]);
        }
        if(opt==3)  //区间询问最大值
        {
            scanf("%d%d",&x,&y);
            x++,y++;
            x=number(x-1),y=number(y+1);
            splay(x,0),splay(y,x);
            printf("%d\n",mx[ch[y][0]]);
        } 
    }
    return 0;
}
/*
4 4
1 1 3 2
3 2 4
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值