1. 题目

传送门= ̄ω ̄=

此题貌似是个权限题,上面那个传送门是到我的 BZOJ 离线题库里的,可以看题但不能提交。如果没权限号的话可以搞标程(比如我的代码哈哈哈)对拍。

不过我还是复制一下题面吧。

更新:突然发现此题 CODEVS 上有(CODEVS-4655),可以不需要权限号。传送门= ̄ω ̄=

1251: 序列终结者

Time Limit: 20 Sec Memory Limit: 162 MB
Submit: 4393 Solved: 1858

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。

2. 题解

splay 练手题一道。

支持区间加、区间翻转、区间最大值就行了。

splay 的区间操作可以参见这篇文章:传送门= ̄ω ̄=

对于文艺平衡树我们就是要多个区间加和区间最大值,多搞一个标记和一个保存最大值的域就行了。

那么我们就在 push_down 的时候判断一下是否打了标记。

关于 push_down 我有点心得:就是一定要保证当前打了标记的节点的各个域的值是正确的!比如这里一定要保证被打了标记的节点的 max(保存最大值)的域正确!

然后 push_up 的时候多了一个 $e[f].max=max(e[f].data,e[l].max,e[r].max)$其中 $f$是父亲节点,也就是被 push_up 的节点,$l$和 $r$分别是左右儿子节点,$max$是最大值域,$data$是这个节点的值。

对于此题还有一个很关键的地方:要设空节点的 max 为-inf(一个极小值)。空节点指的是一个不存在的节点,比如用下标(模拟链表)写的 splay 的话一般就是 0 号节点(详情参见代码)。因为我们 update 叶子节点的时候会查空节点的值,如果大了的话会影响答案的。

总之,看代码吧,还是很简洁的=。=

代码:

#include <bits/stdc++.h>
using namespace std;
template<typename _Tp>inline void IN(_Tp&dig)
{
    char c;bool flag=0;dig=0;
    while(c=getchar(),!isdigit(c))if(c=='-')flag=1;
    while(isdigit(c))dig=dig*10+c-'0',c=getchar();
    if(flag)dig=-dig;
}
struct N{int s[2],f,d,rev,add,sz,mx;}e[50005];
int n,k,data[50005],sz,root;
bool pos(int a){return a==e[e[a].f].s[1];}
void pup(int a)
{
    e[a].sz=e[e[a].s[0]].sz+e[e[a].s[1]].sz+1;
    e[a].mx=max(e[a].d,max(e[e[a].s[0]].mx,e[e[a].s[1]].mx));
}
void pdown(int a)
{
    int&l=e[a].s[0],&r=e[a].s[1];
    if(e[a].add)
    {
        if(l)e[l].add+=e[a].add,e[l].d+=e[a].add,e[l].mx+=e[a].add;
        if(r)e[r].add+=e[a].add,e[r].d+=e[a].add,e[r].mx+=e[a].add;
        e[a].add=0;
    }
    if(e[a].rev)e[l].rev^=1,e[r].rev^=1,swap(l,r),e[a].rev=0;
}
void rot(int a)
{
    int f=e[a].f,g=e[f].f,p=pos(a),q=pos(f);
    pdown(f),pdown(a);
    e[f].s[p]=e[a].s[!p],e[a].s[!p]=f,e[f].f=a;
    if(e[f].s[p])e[e[f].s[p]].f=f;
    if(e[a].f=g)e[g].s[q]=a;
    pup(f),pup(a);
}
void splay(int a,int t)
{
    for(;e[a].f!=t;rot(a))if(e[e[a].f].f!=t)
        if(pos(a)^pos(e[a].f))rot(a);
        else rot(e[a].f);
    if(!t)root=a;
}
int build(int l,int r,int f)
{
    if(l>r)return 0;
    int a=++sz,mid=(l+r)>>1;
    e[a].f=f,e[a].d=e[a].mx=data[mid];
    e[a].s[0]=build(l,mid-1,a),e[a].s[1]=build(mid+1,r,a);
    pup(a);
    return a;
}
int find_by_order(int x)
{
    int a=root;
    while(a)
    {
        pdown(a);
        if(x<=e[e[a].s[0]].sz)a=e[a].s[0];
        else
        {
            x-=e[e[a].s[0]].sz+1;
            if(!x)return a;
            a=e[a].s[1];
        }
    }
    return 0;
}
void get_part(int l,int r)
{
    l=find_by_order(l),r=find_by_order(r+2);
    splay(l,0),splay(r,l);
}
int main()
{
    IN(n),IN(k),e[0].mx=data[1]=data[n+2]=-2e9,root=build(1,n+2,0);
    for(int i=1,K,L,R,V,p;i<=k;i++)
    {
        IN(K),IN(L),IN(R),get_part(L,R),p=e[e[root].s[1]].s[0];
        if(K==1)IN(V),e[p].add+=V,e[p].d+=V,e[p].mx+=V;
        else if(K==2)e[p].rev^=1;
        else printf("%d\n",e[p].mx);
    }
    return 0;
}
分类: 文章

XZYQvQ

炒鸡辣鸡的制杖蒟蒻一枚QvQ

0 条评论

发表回复

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用 * 标注