zoukankan      html  css  js  c++  java
  • BZOJ 1251 序列终结者(Splay)

    题目大意

    网上有许多题,就是给定一个序列,要你支持几种操作: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。

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

    【数据范围】N<=50000,M<=100000。

    做法分析

    这题还真不能用 线段树 做,Splay 是一个不错的选择

    对于操作 1 将所有 [L, R] 中的数加上一个常量,可以对 Splay 树中的节点增加一个 add 域,表示以该节点为根中序遍历所得的数列中每个数要增加 add,每次执行的时候,先将 L-1 旋转到根,再把 R+1 旋转成根的儿子节点,那么,[L, R] 区间的数列就在 R+1 的左子树中了,对 R+1 的左儿子执行更新操作即可,类似于线段树的懒操作

    对于操作 2 将所有 [L, R] 中的数翻转,可以对 Splay 树中的节点增加一个 rev 域,表示以该节点为根中序遍历所得的数列是否需要翻转,更新的时候还是和操作 1 一样,将 L-1 旋转到根,R+1 旋转成为 L-1 的孩子,直接对 R+1 的左儿子更新

    对于操作 3,增加一个 Max 域,表示以该节点为根中序遍历得到的数列中最大值是多少,询问时,将 L-1 旋转到根,R+1 旋转成 L-1 的孩子,询问 R-1 的左儿子的 Max 即可

    这里说一点细节:由于是维护数列,且涉及到区间翻转操作,所以还要增加一个 Size 域,表示以它为根的中序遍历得到的数列的个数是多少,用它来实现数列中的定位

    由于涉及到翻转和统一加权操作,pushDown 和 pushUp 操作一定要想好在哪些地方需要执行

    参考代码

      1 #include <iostream>
      2 #include <cstring>
      3 #include <cstdio>
      4 
      5 using namespace std;
      6 
      7 const int N=100005, INF=0x7fffffff;
      8 
      9 struct Splay_Tree {
     10     struct Node {
     11         int val, Max, add, Size, son[2];
     12         bool rev;
     13         void init(int _val) {
     14             val=Max=_val, Size=1;
     15             add=rev=son[0]=son[1]=0;
     16         }
     17     } T[N];
     18     int fa[N], root;
     19 
     20     void pushUp(int x) {
     21         T[x].Max=T[x].val, T[x].Size=1;
     22         if(T[x].son[0]) {
     23             T[x].Max=max(T[x].Max, T[T[x].son[0]].Max);
     24             T[x].Size+=T[T[x].son[0]].Size;
     25         }
     26         if(T[x].son[1]) {
     27             T[x].Max=max(T[x].Max, T[T[x].son[1]].Max);
     28             T[x].Size+=T[T[x].son[1]].Size;
     29         }
     30     }
     31 
     32     void pushDown(int x) {
     33         if(x==0) return;
     34         if(T[x].add) {
     35             if(T[x].son[0]) {
     36                 T[T[x].son[0]].val+=T[x].add;
     37                 T[T[x].son[0]].Max+=T[x].add;
     38                 T[T[x].son[0]].add+=T[x].add;
     39             }
     40             if(T[x].son[1]) {
     41                 T[T[x].son[1]].val+=T[x].add;
     42                 T[T[x].son[1]].Max+=T[x].add;
     43                 T[T[x].son[1]].add+=T[x].add;
     44             }
     45             T[x].add=0;
     46         }
     47         if(T[x].rev) {
     48             if(T[x].son[0]) T[T[x].son[0]].rev^=1;
     49             if(T[x].son[1]) T[T[x].son[1]].rev^=1;
     50             swap(T[x].son[0], T[x].son[1]);
     51             T[x].rev=0;
     52         }
     53     }
     54 
     55     void Rotate(int x, int kind) {
     56         int y=fa[x], z=fa[y];
     57         T[y].son[!kind]=T[x].son[kind], fa[T[x].son[kind]]=y;
     58         T[x].son[kind]=y, fa[y]=x;
     59         T[z].son[T[z].son[1]==y]=x, fa[x]=z;
     60         pushUp(y);
     61     }
     62 
     63     void Splay(int x, int goal) {
     64         if(x==goal) return;
     65         while(fa[x]!=goal) {
     66             int y=fa[x], z=fa[y];
     67             pushDown(z), pushDown(y), pushDown(x);
     68             int rx=T[y].son[0]==x, ry=T[z].son[0]==y;
     69             if(z==goal) Rotate(x, rx);
     70             else {
     71                 if(rx==ry) Rotate(y, ry);
     72                 else Rotate(x, rx);
     73                 Rotate(x, ry);
     74             }
     75         }
     76         pushUp(x);
     77         if(goal==0) root=x;
     78     }
     79 
     80     int Select(int pos) {
     81         int u=root;
     82         pushDown(u);
     83         while(T[T[u].son[0]].Size!=pos) {
     84             if(pos<T[T[u].son[0]].Size) u=T[u].son[0];
     85             else {
     86                 pos-=T[T[u].son[0]].Size+1;
     87                 u=T[u].son[1];
     88             }
     89             pushDown(u);
     90         }
     91         return u;
     92     }
     93 
     94     void update(int L, int R, int val) {
     95         int u=Select(L-1), v=Select(R+1);
     96         Splay(u, 0);
     97         Splay(v, u);
     98         T[T[v].son[0]].Max+=val;
     99         T[T[v].son[0]].val+=val;
    100         T[T[v].son[0]].add+=val;
    101     }
    102 
    103     void Reverse(int L, int R) {
    104         int u=Select(L-1), v=Select(R+1);
    105         Splay(u, 0);
    106         Splay(v, u);
    107         T[T[v].son[0]].rev^=1;
    108     }
    109 
    110     int query(int L, int R) {
    111         int u=Select(L-1), v=Select(R+1);
    112         Splay(u, 0);
    113         Splay(v, u);
    114         return T[T[v].son[0]].Max;
    115     }
    116 
    117     int build(int L, int R) {
    118         if(L>R) return 0;
    119         if(L==R) return L;
    120         int mid=(L+R)>>1, sL, sR;
    121         T[mid].son[0]=sL=build(L, mid-1);
    122         T[mid].son[1]=sR=build(mid+1, R);
    123         fa[sL]=fa[sR]=mid;
    124         pushUp(mid);
    125         return mid;
    126     }
    127 
    128     void init(int n) {
    129         T[0].init(-INF), T[1].init(-INF), T[n+2].init(-INF);
    130         for(int i=2; i<=n+1; i++) T[i].init(0);
    131         root=build(1, n+2), fa[root]=0;
    132         fa[0]=0, T[0].son[1]=root, T[0].Size=0;
    133     }
    134 };
    135 
    136 Splay_Tree hehe;
    137 
    138 int main() {
    139     int n, m;
    140     scanf("%d%d", &n, &m);
    141     hehe.init(n);
    142     for(int i=0, a, b, c, d; i<m; i++) {
    143         scanf("%d", &a);
    144         if(a==1) {
    145             scanf("%d%d%d", &b, &c, &d);
    146             hehe.update(b, c, d);
    147         }
    148         else if(a==2) {
    149             scanf("%d%d", &b, &c);
    150             hehe.Reverse(b, c);
    151         }
    152         else {
    153             scanf("%d%d", &b, &c);
    154             printf("%d
    ", hehe.query(b, c));
    155         }
    156     }
    157     return 0;
    158 }
    BZOJ 1251

    题目链接 & AC 通道

    BZOJ 1251 序列终结者

  • 相关阅读:
    浅谈三层架构
    尺度空间(Scale space)理论
    漫游Kafka实现篇之消息和日志
    杭电 2095
    .net调用Outlook 批量发送邮件,可指定Outlook中的账号来发送邮件
    Java实现 蓝桥杯VIP 算法提高 计算时间
    Java实现 蓝桥杯VIP 算法提高 计算时间
    Java实现 蓝桥杯VIP 算法提高 计算时间
    Java实现 蓝桥杯VIP 算法提高 计算时间
    Java实现 蓝桥杯VIP 算法提高 最小乘积(提高型)
  • 原文地址:https://www.cnblogs.com/zhj5chengfeng/p/3269206.html
Copyright © 2011-2022 走看看