Codeforces 1139F Dish Shopping 树状数组套平衡树 || 平衡树

Dish Shopping

将每个物品拆成p 和 s 再加上人排序。 然后问题就变成了, 对于一个线段(L - R),

问有多少个(li, ri)满足  L >= li && R >= ri, 这个东西可以直接树状数组套平衡树维护。

但是这个题目有个特殊性,因为排好序之后不会存在 li > L && ri > R的点, 所以可以直接

用平衡树, 或者线段树去维护这个东西。

平板电视

#include<bits/stdc++.h>
#include <bits/extc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ull unsigned long long

using namespace std;
using namespace __gnu_pbds;

const int N = 1e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const double eps = 1e-6;
const double PI = acos(-1);

int n, m, tot, ans[N * 3], hs[N], cnt;
int p[N], s[N], b[N], inc[N], pref[N];

struct event {
    int p, b, id, op, rp;
    bool operator < (const event& rhs) const {
        if(p == rhs.p) return op < rhs.op;
        else return p < rhs.p;
    }
} e[N * 3];

template <class T>
using Tree = tree<T, null_type, std::less<T>, rb_tree_tag,tree_order_statistics_node_update>;

struct Bit {
    Tree<PII> T[N];
    void add(int x, PII v) {
        for(int i = x; i <= cnt; i += i & -i)
            T[i].insert(v);
    }
    void del(int x, PII v) {
        for(int i = x; i <= cnt; i += i & -i)
            T[i].erase(v);
    }
    int sum(int x, int R) {
        int ans = 0;
        for(int i = x; i; i -= i & -i)
            ans += T[i].order_of_key(mk(R, INT_MAX));
        return ans;
    }
} bit;

int getPos(int x) {
    return upper_bound(hs + 1, hs + 1 + cnt, x) - hs - 1;
}

int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) scanf("%d", &p[i]);
    for(int i = 1; i <= n; i++) scanf("%d", &s[i]);
    for(int i = 1; i <= n; i++) scanf("%d", &b[i]);
    for(int i = 1; i <= n; i++) {
        e[++tot] = event{p[i], b[i], i, 0, p[i]};
        e[++tot] = event{s[i], b[i], i, 2, p[i]};
        hs[++cnt] = p[i] - b[i];
    }
    for(int i = 1; i <= m; i++) scanf("%d", &inc[i]);
    for(int i = 1; i <= m; i++) scanf("%d", &pref[i]);
    for(int i = 1; i <= m; i++) e[++tot] = event{inc[i], pref[i], n + i, 1, 0};

    sort(hs + 1, hs + 1 + cnt);
    cnt = unique(hs + 1, hs + 1 + cnt) - hs - 1;

    sort(e + 1, e + 1 + tot);
    for(int i = 1; i <= tot; i++) {
        int p = e[i].p, b = e[i].b, rp = e[i].rp;
        if(e[i].op == 0) {
            bit.add(getPos(rp - b), mk(rp + b, e[i].id));
        } else if(e[i].op == 1) {
            ans[e[i].id] = bit.sum(getPos(p - b), p + b);
        } else {
            bit.del(getPos(rp - b), mk(rp + b, e[i].id));
        }
    }
    for(int i = n + 1; i <= n + m; i++) printf("%d ", ans[i]);
    puts("");
    return 0;
 }

/*
*/

treap, 为啥我的treap好慢啊啊啊。

#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ull unsigned long long

using namespace std;

const int N = 1e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const double eps = 1e-6;
const double PI = acos(-1);

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

int n, m, tot, ans[N * 3], hs[N], cnt;
int p[N], s[N], b[N], inc[N], pref[N];

struct event {
    int p, b, id, op, rp;
    bool operator < (const event& rhs) const {
        if(p == rhs.p) return op < rhs.op;
        else return p < rhs.p;
    }
} e[N * 3];

struct node {
    node* ch[2];
    int key, fix, sz, cnt;
    void update() {
        sz = ch[0]->sz + ch[1]->sz + cnt;
    }
} base[N * 20];

typedef node* P_node;
P_node len = base;

struct Treap {
    node nil;
    P_node root, null;
    Treap() {
        root = null = &nil;
        null->key = null->fix = inf;
        null->sz = null->cnt = 0;
        null->ch[0] = null->ch[1] = null;
    }
    P_node newnode(int tkey) {
        len->key = tkey;
        len->fix = rng();
        len->ch[0] = len->ch[1] = null;
        len->sz = len->cnt = 1;
        return len++;
    }
    void rot(P_node &p, int d) {
        P_node k = p->ch[d ^ 1];
        p->ch[d ^ 1] = k->ch[d];
        k->ch[d] = p;
        p->update();
        k->update();
        p = k;
    }
    void _Insert(P_node &p, int tkey) {
        if(p == null) {
            p = newnode(tkey);
        } else if(p->key == tkey) {
            p->cnt++;
        } else {
            int d = tkey > p->key;
            _Insert(p->ch[d], tkey);
            if(p->ch[d]->fix > p->fix) {
                rot(p, d ^ 1);
            }
        }
        p->update();
    }

    void _Delete(P_node &p, int tkey) {
        if(p == null) return;
        if(p->key == tkey) {
            if(p->cnt > 1) p->cnt--;
            else if(p->ch[0] == null) p = p->ch[1];
            else if(p->ch[1] == null) p = p->ch[0];
            else {
                int d = p->ch[0]->fix > p->ch[1]->fix;
                rot(p, d);
                _Delete(p->ch[d], tkey);
            }
        } else {
            _Delete(p->ch[tkey > p->key], tkey);
        }
        p->update();
    }
    int _Kth(P_node p, int k) {
        if(p == null || k < 1 || k > p->sz) return 0;
        if(k < p->ch[0]->sz + 1) return _Kth(p->ch[0], k);
        if(k > p->ch[0]->sz + p->cnt) return _Kth(p->ch[1], k - p->ch[0]->sz - p->cnt);
        return p->key;
    }
    int _Rank(P_node p, int tkey, int res) {
        if(p == null) return -1;
        if(p->key == tkey) return p->ch[0]->sz + res + 1;
        if(tkey < p->key) return _Rank(p->ch[0], tkey, res);
        return _Rank(p->ch[1], tkey, res + p->ch[0]->sz + p->cnt);
    }
    int _Pred(P_node p, int tkey){
        if(p == null) return -inf;
        if(tkey <= p->key) return _Pred(p->ch[0], tkey);
        return max(p->key, _Pred(p->ch[1], tkey));
    }
    int _Succ(P_node p, int tkey){
        if(p == null) return inf;
        if(tkey >= p->key) return _Succ(p->ch[1], tkey);
        return min(p->key, _Succ(p->ch[0], tkey));
    }
    int _Query(P_node p, int tkey) {
        if(p == null) return 0;
        if(p->key > tkey) return _Query(p->ch[0], tkey);
        else if(p->key < tkey) return p->cnt + p->ch[0]->sz + _Query(p->ch[1], tkey);
        else return p->cnt + p->ch[0]->sz;
    }
    void Insert(int tkey){ _Insert(root,tkey); }
    void Delete(int tkey){ _Delete(root,tkey); }
    int Kth(int k){ return _Kth(root,k); }
    int Rank(int tkey){ return _Rank(root,tkey,0); }
    int Pred(int tkey){ return _Pred(root,tkey); }
    int Succ(int tkey){ return _Succ(root,tkey); }
    int Query(int tkey){ return _Query(root, tkey); }
}tp;

struct Bit {
    Treap T[N];
    void add(int x, int v) {
        for(int i = x; i <= cnt; i += i & -i)
            T[i].Insert(v);
    }
    void del(int x, int v) {
        for(int i = x; i <= cnt; i += i & -i)
            T[i].Delete(v);
    }
    int sum(int x, int R) {
        int ans = 0;
        for(int i = x; i; i -= i & -i)
            ans += T[i].Query(R);
        return ans;
    }
} bit;

int getPos(int x) {
    return upper_bound(hs + 1, hs + 1 + cnt, x) - hs - 1;
}

int main() {
    srand(time(NULL));
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) scanf("%d", &p[i]);
    for(int i = 1; i <= n; i++) scanf("%d", &s[i]);
    for(int i = 1; i <= n; i++) scanf("%d", &b[i]);
    for(int i = 1; i <= n; i++) {
        e[++tot] = event{p[i], b[i], i, 0, p[i]};
        e[++tot] = event{s[i], b[i], i, 2, p[i]};
        hs[++cnt] = p[i] - b[i];
    }
    for(int i = 1; i <= m; i++) scanf("%d", &inc[i]);
    for(int i = 1; i <= m; i++) scanf("%d", &pref[i]);
    for(int i = 1; i <= m; i++) e[++tot] = event{inc[i], pref[i], n + i, 1, 0};

    sort(hs + 1, hs + 1 + cnt);
    cnt = unique(hs + 1, hs + 1 + cnt) - hs - 1;

    sort(e + 1, e + 1 + tot);
    for(int i = 1; i <= tot; i++) {
        int p = e[i].p, b = e[i].b, rp = e[i].rp;
        if(e[i].op == 0) {
            bit.add(getPos(rp - b), rp + b);
        } else if(e[i].op == 1) {
            ans[e[i].id] = bit.sum(getPos(p - b), p + b);
        } else {
            bit.del(getPos(rp - b), rp + b);
        }
    }
    for(int i = n + 1; i <= n + m; i++) printf("%d ", ans[i]);
    puts("");
    return 0;
 }

/*
*/

原文地址:https://www.cnblogs.com/CJLHY/p/10612071.html

时间: 2024-08-04 15:59:28

Codeforces 1139F Dish Shopping 树状数组套平衡树 || 平衡树的相关文章

BZOJ3295 动态逆序对 树套树, 树状数组套线段树(主席树)

Orz黄学长,蒟蒻在黄学长的带领下,通过阅读黄学长的代码!终于会了这道题! 首先我想先说一下这道题的思路(准确来说是黄学长的). 很明显,树状数组应该不用讲吧!关键是内存怎么开,维护一些什么样的数据? 其实我们通过观察,很快可以发现,你维护被删的数比维护所有的数轻松多了(不管是空间上,还是时间上).所以我们就可以从这方面想!(其实我一开始的思路,因为这道题我已经看过很久了,一直想写,毕竟是白书里面的一道例题嘛!一开始,蒟蒻的我是打算这样的用树状数组套权值线段树,并且是维护所有的数,我发现空间不够

3110: [Zjoi2013]K大数查询 树状数组套线段树

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1384  Solved: 629[Submit][Status] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a b c或2 a b

BZOJ 3196 Tyvj 1730 二逼平衡树 ——树状数组套主席树

[题目分析] 听说是树套树.(雾) 怒写树状数组套主席树,然后就Rank1了.23333 单点修改,区间查询+k大数查询=树状数组套主席树. [代码] #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <set> #include <map> #include <string> #include <alg

[BZOJ 3196] 二逼平衡树 树状数组套主席树

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3357  Solved: 1326[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为

【BZOJ】1047: [HAOI2007]理想的正方形(单调队列/~二维rmq+树状数组套树状数组)

http://www.lydsy.com/JudgeOnline/problem.php?id=1047 树状数组套树状数组真心没用QAQ....首先它不能修改..而不修改的可以用单调队列做掉,而且更快,只有O(n^2).而这货是n^2log^2n的建树...虽然查询是log^2n...但是建树那里就tle了.. 那么说题解... 先orz下,好神.. 我怎么没想到单调队列orz 首先我们维护 行 的单调队列,更新每个点在 列 距离内的最小and最大的值 然后我们维护 列 的单调队列,更新每个点

[BZOJ 3196] 213平衡树 【线段树套set + 树状数组套线段树】

题目链接:BZOJ - 3196 题目分析 区间Kth和区间Rank用树状数组套线段树实现,区间前驱后继用线段树套set实现. 为了节省空间,需要离线,先离散化,这样需要的数组大小可以小一些,可以卡过128MB = = 嗯就是这样,代码长度= =我写了260行......Debug了n小时= = 代码 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #in

[BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log n). 代码 树状数组套线段树 #include <iostream> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> usin

Bestcoder7(1004)hdu4988(经典问题:树状数组套treap求解动态逆序对)

Little Pony and Boast Busters Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 83    Accepted Submission(s): 32 Problem Description "I hereby challenge you, Ponyvillians: anything you can do

【树状数组套权值线段树】bzoj1901 Zju2112 Dynamic Rankings

谁再管这玩意叫树状数组套主席树我跟谁急 明明就是树状数组的每个结点维护一棵动态开结点的权值线段树而已 好吧,其实只有一个指针,指向该结点的权值线段树的当前结点 每次查询之前,要让指针指向根结点 不同结点的权值线段树之间毫无关联 可以看这个:http://blog.csdn.net/popoqqq/article/details/40108669?utm_source=tuicool #include<cstdio> #include<algorithm> using namespa