[LUOGU4146]序列终结者(Fhq_Treap)

Posted by Dispwnl on March 21, 2018

谨以此纪念一个浪费的下午

今天本来是想看看数论的…

可为什么全用来搞平衡树了喂!T_T

题目

题目背景

网上有许多题,就是给定一个序列,要你支持几种操作:A、B、C、D。一看另一道题,又是一个序列

要支持几种操作:D、C、B、A。尤其是我们这里的某人,出模拟试题,居然还出了一道这样的,真是没技术含量……这样

我也出一道题,我出这一道的目的是为了让大家以后做这种题目有一个“库”可以依靠,没有什么其他的意思。这道题目

就叫序列终结者吧。

题目描述

给定一个长度为N的序列,每个序列的元素是一个整数(废话)。要支持以下三种操作:

将$[L,R]$这个区间内的所有数加上$V$。

将$[L,R]$这个区间翻转,比如1 2 3 4变成4 3 2 1。

求$[L,R]$这个区间中的最大值。最开始所有元素都是0。

输入输出格式

输入格式:

第一行两个整数N,M。M为操作个数。

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

输出格式:

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

输入输出样例

输入样例#1:

4 4
1 1 3 2
1 2 4 -1
2 1 3
3 2 4

输出样例#1:

2

说明

$N\leq 50000,M\leq 100000$。

题解

序列终结者这题我本来是用$splay$搞的然后知道$Fhq$ $Treap$可以搞区间就与$splay$说拜拜了

然后今天想用ta练练$Fhq$ $Treap$

操作都挺简单,建树直接暴力建高级建法我不会啊,然后搞一大堆$merge$ $split$,处理两个标记

然后就开心的打完了

然后就WA了不这不可能这是评测姬的锅。。。

尴尬的检查了一下午竟然没找出错。。。

无意瞄了一眼输出函数

woccccc $split$为什么从$l$开始分啊我明明是粘的板子

改过了就A了T_T竟然跑的比$splay$慢

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<cstdlib>
using namespace std;
const int MAX=5e4+1;
int tot,rt;
int max(int x,int y)
{
    return x>y?x:y;
}
int read()
{
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);f=(ch=='-')?-1:1,ch=getchar());
    for(;isdigit(ch);x=x*10+ch-48,ch=getchar());
    return x*f;
}
struct Fhq_Treap{
    int w[MAX],siz[MAX],lazy[MAX],maxn[MAX],pos[MAX];
    int son[MAX][2];
    bool fl[MAX];
    void pus(int x)
    {
        siz[x]=siz[son[x][1]]+siz[son[x][0]]+1;
        if(son[x][1]&&son[x][0]) maxn[x]=max(w[x],max(maxn[son[x][1]],maxn[son[x][0]]));
        else if(son[x][1]) maxn[x]=max(w[x],maxn[son[x][1]]);
        else if(son[x][0]) maxn[x]=max(w[x],maxn[son[x][0]]);
        else maxn[x]=w[x];
    }
    void rever(int x)
    {
        swap(son[x][0],son[x][1]);
        fl[x]^=1;
    }
    void add(int x,int v)
    {
        lazy[x]+=v,maxn[x]+=v,w[x]+=v;
    }
    void down(int x)
    {
        if(fl[x]&&x)
        {
            if(son[x][1]) rever(son[x][1]);
            if(son[x][0]) rever(son[x][0]);
            fl[x]=0;
        }
        if(lazy[x]&&x)
        {
            if(son[x][1]) add(son[x][1],lazy[x]);
            if(son[x][0]) add(son[x][0],lazy[x]);
            lazy[x]=0;
        }
    }
    int merge(int x,int y)
    {
        if(x) down(x);
        if(y) down(y);
        if(!x||!y) return x+y;
        if(pos[x]<pos[y])
        {
            son[x][1]=merge(son[x][1],y);
            pus(x);
            return x;
        }
        else
        {
            son[y][0]=merge(x,son[y][0]);
            pus(y);
            return y;
        }
    }
    void split(int i,int k,int &a,int &b)
    {
        if(!i) a=b=0;
        else
        {
            down(i);
            if(k<=siz[son[i][0]])
            b=i,split(son[i][0],k,a,son[i][0]);
            else
            a=i,split(son[i][1],k-siz[son[i][0]]-1,son[i][1],b);
            pus(i);
        }
    }
    void ins(int l)
    {
        int a,b;
        split(rt,l,a,b);
        pos[++tot]=rand();
        rt=merge(merge(a,tot),b);
    }
    void ADD(int l,int r,int x)
    {
        int L=r-l+1;
        int a,b,c,d;
        split(rt,l-1,a,b);
        split(b,L,c,d);
        add(c,x);
        rt=merge(a,merge(c,d));
    }
    void REVER(int l,int r)
    {
        int L=r-l+1;
        int a,b,c,d;
        split(rt,l-1,a,b);
        split(b,L,c,d);
        rever(c);
        rt=merge(a,merge(c,d));
    }
    void GET_MAX(int l,int r)
    {
        int L=r-l+1;
        int a,b,c,d;
        split(rt,l-1,a,b);
        split(b,L,c,d);
        printf("%d\n",maxn[c]);
        rt=merge(a,merge(c,d));
    }
}Tree;
int n,m;
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;++i)
      Tree.ins(i);
    for(int i=1;i<=m;++i)
      {
      	int op=read(),l=read(),r=read();
      	if(op==1)
      	Tree.ADD(l,r,read());
      	else if(op==2)
      	Tree.REVER(l,r);
      	else if(op==3)
      	Tree.GET_MAX(l,r);
      }
    return 0;
}