#4864. [BeiJing 2017 Wc]神秘物质 [FHQ Treap]

这题其实挺简单的,有个东西可能稍微难维护了一点点。。

\(merge\ x\ e\) 当前第 \(x\) 个原子和第 \(x+1\) 个原子合并,得到能量为 \(e\) 的新原子;
\(insert\ x\ e\) 在当前第 \(x\) 个原子和第 \(x+1\) 个原子之间插入一个能量为 \(e\) 的新原子。
\(max\ x\ y\) 当前第 \(x\) 到第 \(y\) 个原子之间的任意子区间中区间极差的最大值;
\(min\ x\ y\) 当前第 \(x\) 到第 \(y\) 个原子之间的任意子区间中区间极差的最小值。

极差最大值其实很显然是个区间 \(max - min\)
极差最小的区间呢,长度至少为 \(2\) 也必须为 \(2\)
至于证明的话
考虑 \(x,y,z\)

如果 \(x\) 和 \(z\) 的差的绝对值是解,那么 \(|x-y|\) 或者 \(|y-z|\) 一定更优

因为 \(x \leq y \leq z\) 才符合这种情况。

所以随便写写,把相邻两个的差变成后一个点的值,随便写写就可以了。

// by Isaunoya
#include <bits/stdc++.h>
using namespace std;
#define rep(i, x, y) for (register int i = (x); i <= (y); ++i)
#define Rep(i, x, y) for (register int i = (x); i >= (y); --i)

const int _ = 1 << 21;
struct I {
    char fin[_], *p1 = fin, *p2 = fin;
    inline char gc() {
        return (p1 == p2) && (p2 = (p1 = fin) + fread(fin, 1, _, stdin), p1 == p2) ? EOF : *p1++;
    }
    inline I& operator>>(int& x) {
        bool sign = 1;
        char c = 0;
        while (c < 48) ((c = gc()) == 45) && (sign = 0);
        x = (c & 15);
        while ((c = gc()) > 47) x = (x << 1) + (x << 3) + (c & 15);
        x = sign ? x : -x;
        return *this;
    }
    inline I& operator>>(double& x) {
        bool sign = 1;
        char c = 0;
        while (c < 48) ((c = gc()) == 45) && (sign = 0);
        x = (c - 48);
        while ((c = gc()) > 47) x = x * 10 + (c - 48);
        if (c == '.') {
            double d = 1.0;
            while ((c = gc()) > 47) d = d * 0.1, x = x + (d * (c - 48));
        }
        x = sign ? x : -x;
        return *this;
    }
    inline I& operator>>(char& x) {
        do
            x = gc();
        while (isspace(x));
        return *this;
    }
    inline I& operator>>(string& s) {
        s = "";
        char c = gc();
        while (isspace(c)) c = gc();
        while (!isspace(c) && c != EOF) s += c, c = gc();
        return *this;
    }
} in;
struct O {
    char st[100], fout[_];
    signed stk = 0, top = 0;
    inline void flush() {
        fwrite(fout, 1, top, stdout), fflush(stdout), top = 0;
    }
    inline O& operator<<(int x) {
        if (top > (1 << 20)) flush();
        if (x < 0) fout[top++] = 45, x = -x;
        do
            st[++stk] = x % 10 ^ 48, x /= 10;
        while (x);
        while (stk) fout[top++] = st[stk--];
        return *this;
    }
    inline O& operator<<(char x) {
        fout[top++] = x;
        return *this;
    }
    inline O& operator<<(string s) {
        if (top > (1 << 20)) flush();
        for (char x : s) fout[top++] = x;
        return *this;
    }
} out;
#define pb emplace_back
#define fir first
#define sec second

template < class T > inline void cmax(T & x , const T & y) {
    (x < y) && (x = y) ;
}
template < class T > inline void cmin(T & x , const T & y) {
    (x > y) && (x = y) ;
}

int n , m , rt = 0 ;
const int N = 2e5 + 10 ;
int a[N] ;
const int inf = 0x7fffffff ;
int rnd[N] , val[N] , mx[N] , mn[N] , ch[N][2] , sz[N] ;
int cnt = 0 ;
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
int newnode(int v) {
    ++ cnt ;
    val[cnt] = mx[cnt] = mn[cnt] = v ;
    rnd[cnt] = rand() ;
    sz[cnt] = 1 ;
    return cnt ;
}
int t[N] , s[N] ;
void pushup(int rt) {
    mx[rt] = mn[rt] = val[rt] ;
    if(ls(rt)) cmin(mn[rt] , mn[ls(rt)]) , cmax(mx[rt] , mx[ls(rt)]) ;
    if(rs(rt)) cmin(mn[rt] , mn[rs(rt)]) , cmax(mx[rt] , mx[rs(rt)]) ;
    sz[rt] = sz[ls(rt)] + sz[rs(rt)] + 1 ;
    t[rt] = min(t[ls(rt)] , t[rs(rt)]) , cmin(t[rt] , s[rt]) ;
}
int merge(int u , int v) {
    if(! u || ! v) return u | v ;
    if(rnd[u] < rnd[v]) {
        rs(u) = merge(rs(u) , v) ;
        pushup(u) ;
        return u ;
    } else {
        ls(v) = merge(u , ls(v)) ;
        pushup(v) ;
        return v ;
    }
}
void split(int cur , int k , int & u , int & v) {
    if(! cur) {
        u = v = 0 ;
        return ;
    }
    if(k <= sz[ls(cur)]) {
        v = cur ;
        split(ls(v) , k , u , ls(v)) ;
    } else {
        u = cur ;
        split(rs(u) , k - sz[ls(u)] - 1 , rs(u) , v) ;
    }
    pushup(cur) ;
}
void ins(int k , int v) {
    int x , y , z , xx ;
    split(rt , k - 1 , x , y) ;
    split(y , 1 , y , z) ;
    split(z , 1 , z , xx) ;
    int now = newnode(v) ;
    t[now] = s[now] = abs(val[now] - val[y]) ;
    if(! y) {
        t[now] = s[now] = inf ;
    }
    t[z] = s[z] = abs(val[z] - val[now]) ;
    if(! z) {
        t[z] = s[z] = inf ;
    }
    rt = merge(merge(merge(merge(x , y) , now) , z) , xx) ;
}
void _merge(int k , int v) {
    int x , y , z , xx ;
    split(rt , k - 1 , x , y) ;
    split(y , 1 , y , z) ;
    split(z , 1 , z , xx) ;
    rt = merge(x , xx) ;
    ins(k - 1 , v) ;
}
int qrymax(int l , int r) {
    int x , y , z ;
    split(rt , r , x , z) ;
    split(x , l - 1 , x , y) ;
    int res = mx[y] - mn[y] ;
    rt = merge(merge(x , y) , z) ;
    return res ;
}
int qrymin(int l , int r) {
    ++ l ;
    int x , y , z ;
    split(rt , r , x , z) ;
    split(x , l - 1 , x , y) ;
    int res = t[y] ;
    rt = merge(merge(x , y) , z) ;
    return res ;
}
void dfs(int u) {
    if(ls(u)) dfs(ls(u)) ;
    out << val[u] << '\n' ;
    if(rs(u)) dfs(rs(u)) ;
}
signed main() {
#ifdef _WIN64
    freopen("testdata.in" , "r" , stdin) ;
#endif
    in >> n >> m ;
    rep(i , 1 , n) in >> a[i] ;
    rt = newnode(a[1]) ;
    t[rt] = s[rt] = inf ;
    rep(i , 2 , n) ins(i - 1 , a[i]) ;
    rep(i , 1 , m) {
        string s ;
        in >> s ;
        int x , y ;
        in >> x >> y ;
        if(s == "max") out << qrymax(x , y) << '\n' ;
        if(s == "min") out << qrymin(x , y) << '\n' ;
        if(s == "merge") _merge(x , y) ;
        if(s == "insert") ins(x , y) ;
    }
    return out.flush(), 0;
}

原文地址:https://www.cnblogs.com/Isaunoya/p/12208778.html

时间: 2024-10-30 22:58:39

#4864. [BeiJing 2017 Wc]神秘物质 [FHQ Treap]的相关文章

【bzoj4864】[BeiJing 2017 Wc]神秘物质 Splay

原文地址:http://www.cnblogs.com/GXZlegend/p/6801631.html 题目描述 21ZZ 年,冬. 小诚退休以后, 不知为何重新燃起了对物理学的兴趣. 他从研究所借了些实验仪器,整天研究各种微观粒子.这一天, 小诚刚从研究所得到了一块奇异的陨石样本, 便迫不及待地开始观测. 在精密仪器的视野下,构成陨石的每个原子都无比清晰. 小诚发现, 这些原子排成若干列, 每一列的结构具有高度相似性.于是,他决定对单独一列原子进行测量和测试.被选中的这列共有 N 个顺序排列

bzoj4864: [BeiJing 2017 Wc]神秘物质

这道题维护区间极差的最小值 只有长度为二的区间有贡献 这个可以尝试画一下 自己想想 这样之后维护的值有 区间最小值 区间最大值 以及区间内长度为二的区间差的最小值 区间大小 点本身的值. 注意要看你维护的区间差在区间左点还是右点 这在查询min的时候很重要 剩下的自己看把 代码不算长的了 虽然有点慢 换成结构体应该会快很多 #include<cstdio> #include<cstring> #include<algorithm> using namespace std

【bzoj1251】序列终结者——fhq treap

Description 给定一个长度为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种操作,给出正确的回答. Sampl

【Foreign】神秘物质 [Splay]

神秘物质 Time Limit: 10 Sec  Memory Limit: 256 MB Description Input Output Sample Input Sample Output 1 2 1 5 HINT Main idea 每个点有一个权值,维护一个结构,支持合并相邻两点,删除单点,加入单点,查询区间子集极差的最大值和最小值. Solution 首先我们可以发现,区间子集极差的最大值显然就是整个区间的最大值-区间最小值,然后区间子集极差最小值只有相邻点的才会产生贡献. 那么我们

【POJ2761】【fhq treap】A Simple Problem with Integers

Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval. In

FHQ Treap小结(神级数据结构!)

首先说一下, 这个东西可以搞一切bst,treap,splay所能搞的东西 pre 今天心血来潮, 想搞一搞平衡树, 先百度了一下平衡树,发现正宗的平衡树写法应该是在二叉查找树的基础上加什么左左左右右左右右的旋转之类的, 思路比较好理解,但是 代码量........ 一看就头大,, 然后,在洛谷翻题解的时候无意间看到了远航之曲发的一篇非常短小精悍的题解, 于是就学了一下 FHQ Treap 这个东西的学名应该是叫做fhq treap,应该是treap的强化版. 整个数据结构中只有两个操作: 1.

浅谈fhq treap

一.简介 fhq treap 与一般的treap主要有3点不同 1.不用旋转 2.以merge和split为核心操作,通过它们的组合实现平衡树的所有操作 3.可以可持久化 二.核心操作 代码中val表示节点权值,pri表示节点的优先级,维护小根堆 1.split 将1个treap分裂为两个treap 分裂主要有两种:以权值k作为分界点.以位置k作为分界点 ①以权值k作为分界点 设原来的treap根节点为root,分裂后的<=k的treap A 的根节点为x,>k的treap B 的根节点为y

fhq treap

fhq-treap 小结 粗浅地学习了这个神奇的数据结构,下面瞎写一些感受 首先fhq treap是一个基于分裂与合并的平衡树,那么怎么分裂,怎么合并呢 我们分两种情况考虑 一.权值平衡树(我自己取的名字) 所谓权值平衡树,就是任何操作都只与权值有关的平衡树 比如最基础的分裂,合并操作 分裂就是把平衡树按照权值\(k\)分成两半,一边所有点的权值\(\leq k\),另一边权值\(\gt k\) 怎么分裂呢 首先根据\(treap\)的定义,所有点的权值是一颗二叉搜索树(BST),就是左边比他小

平衡树合集(Treap,Splay,替罪羊,FHQ Treap)

今天翻了翻其他大佬的博客,发现自己有些...颓废... 有必要洗心革面,好好学习 序:正常的BST有可能退化,成为链,大大降低效率,所以有很多方法来保持左右size的平衡,本文将简单介绍Treap,Splay,替罪羊,FHQ Treap: 另:代码都是普通平衡树 1.Treap 树堆,在数据结构中也称Treap,是指有一个随机附加域满足堆的性质的二叉搜索树,其结构相当于以随机数据插入的二叉搜索树.其基本操作的期望时间复杂度为O(logn).相对于其他的平衡二叉搜索树,Treap的特点是实现简单,