题目网址

【传送门】

题目大意

请你设计一个数据结构,支持单点修改,区间查询排名k。

感想(以下省略脏话inf个字)

真的强力吹爆洛谷数据,一般的树套树还给我T了一般的点,加强的待修主席树还给我卡了几发空间。
我一共交了15发,正确率被这道题目拉低了。。。
……

分析

好像有人用了分块水过这道题目,然后被管理员的加强数据卡到怀疑人生。。。 (不讲骚话了)
考虑最简单的树套树,二逼平衡树的那个,【传送门】
但是这里肯定是T掉了。
nlog3n在加强数据中会跑到\(4 \times 10^8\)。别想用这个方法水过去了。
附加去世代码:

#include <bits/stdc++.h>
#define ll long long
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
#define N 100005
#define lc (nod << 1)
#define rc (nod << 1 | 1)
using namespace std;
template <typename T>
inline void read(T &x) {
    x = 0; T fl = 1; char ch = 0;
    for (; ch < '0' || ch > '9'; ch = getchar())
        if (ch == '-') fl = -1;
    for (; ch >= '0' && ch <= '9'; ch = getchar())
        x = (x << 1) + (x << 3) + (ch ^ 48);
    x *= fl;
}
struct node {
    int cnt, val, sz, ch[2], rd;
    void init(int x) {
        val = x; sz = cnt = 1; ch[1] = ch[0] = 0; rd = rand() % 100;
    }
}tr[N * 20];
int tot = 0;
int rt[N], a[N];
struct treap {
    #define ls(x) tr[x].ch[0]
    #define rs(x) tr[x].ch[1]
    void pushup(int nod) {
        tr[nod].sz = tr[ls(nod)].sz + tr[rs(nod)].sz + tr[nod].cnt;
    }
    void rotate(int &nod, int d) {
        int k = tr[nod].ch[d];
        tr[nod].ch[d] = tr[k].ch[d ^ 1];
        tr[k].ch[d ^ 1] = nod;
        pushup(nod); pushup(k); nod = k;
    }
    void ins(int &nod, int val) {
        if (!nod) {
            tr[nod = ++ tot].init(val); return;
        }
        tr[nod].sz ++;
        if (tr[nod].val == val) tr[nod].cnt ++;
        else {
            int d = val > tr[nod].val;
            ins(tr[nod].ch[d], val);
            if (tr[nod].rd > tr[tr[nod].ch[d]].rd) rotate(nod, d);
        }
    }
    void del(int &nod, int val) {
        if (!nod) return;
        if (tr[nod].val == val) {
            if (tr[nod].cnt > 1) {
                tr[nod].cnt --; tr[nod].sz --; return;
            }
            int d = tr[ls(nod)].rd > tr[rs(nod)].rd;
            if (ls(nod) == 0 || rs(nod) == 0) nod = ls(nod) + rs(nod);
            else rotate(nod, d), del(nod, val);
        }
        else tr[nod].sz --, del(tr[nod].ch[tr[nod].val < val], val);
    }
    int rk(int nod, int val) {
        if (!nod) return 0;
        if (tr[nod].val == val) return tr[ls(nod)].sz;
        if (tr[nod].val > val) return rk(ls(nod), val);
        else return tr[ls(nod)].sz + tr[nod].cnt + rk(rs(nod), val);
    }
}tp[N << 2];
int n, m;
void build(int nod, int l, int r) {
    for (int i = l; i <= r; i ++) tp[nod].ins(rt[nod], a[i]);
    if (l == r) return;
    int mid = (l + r) >> 1;
    build(lc, l, mid); build(rc, mid + 1, r);
}
int query_rk(int nod, int l, int r, int ql, int qr, int k) {
    if (ql <= l && r <= qr) return tp[nod].rk(rt[nod], k);
    int mid = (l + r) >> 1, res = 0;
    if (ql <= mid) res += query_rk(lc, l, mid, ql, qr, k);
    if (qr > mid) res += query_rk(rc, mid + 1, r, ql, qr, k);
    return res;
}
void update(int nod, int l, int r, int k, int val) {
    tp[nod].del(rt[nod], a[k]); tp[nod].ins(rt[nod], val);
    if (l == r) return;
    int mid = (l + r) >> 1;
    if (k <= mid) update(lc, l, mid, k, val);
    else update(rc, mid + 1, r, k, val);
}
int query_fd(int ql, int qr, int k) {
    int l = 0, r = 1e8, res = -1;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (query_rk(1, 1, n, ql, qr, mid) + 1 <= k) res = mid, l = mid + 1;
        else r = mid - 1;
    }
    return res;
}
int main() {
    srand(time(NULL));
    read(n); read(m);
    for (int i = 1; i <= n; i ++) read(a[i]);
    build(1, 1, n);
    while (m --) {
        char opt[5];
        int x, y, z;
        scanf("%s", opt);
        if (opt[0] == 'Q') {
            read(x); read(y); read(z);
            printf("%d\n", query_fd(x, y, z));
        }
        else {
            read(x); read(y);
            update(1, 1, n, x, y);
            a[x] = y;
        }
    }
    return 0;
}

那么不管上面的东西了。
区间查询排名k,听到这个东西我们就可以想到主席树。
主席树实现这个操作就是,对于每一个数的插入都建一棵线段树,然后每一次查询差值,也就是查询前缀和之间的差。
这个方法依旧适用于这一道题目。
因为有修改的操作,所以普通的主席树就过不掉。
可以比较容易的想到用树状数组来维护前缀和。
前缀和维护的是每一个棵主席树的纵向的前缀和。
然后修改就只需要减掉在修改在加回去。
这个思路是我看着别人代码学到的。
还要离散化一下,因为数据比较大,主席树维护的权值线段树可能会炸掉。

#include <bits/stdc++.h>
#pragma GCC optimize(2)
#define ll long long
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
#define N 4000005
#define lowbit(x) (x & -x)
using namespace std;
template <typename T>
inline void read(T &x) {
    x = 0; T fl = 1; char ch = 0;
    for (; ch < '0' || ch > '9'; ch = getchar())
        if (ch == '-') fl = -1;
    for (; ch >= '0' && ch <= '9'; ch = getchar())
        x = (x << 1) + (x << 3) + (ch ^ 48);
    x *= fl;
}
struct qus_rec {
    int x, y, z;
}qus[N];
int tot = 0, dtot, n, m, a, b;
int v[N], disc[N], rt[N], fg[N], sz[N], ls[N], rs[N], L[N], R[N];
char opt[5];
int find(int x) {
    int l = 1, r = dtot;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (disc[mid] < x) l = mid + 1;
        else r = mid - 1;
    }
    return l;
}
void upd(int lst, int l, int r, int &rt, int w, int x) {
    rt = ++ tot;
    sz[rt] = sz[lst] + x; ls[rt] = ls[lst]; rs[rt] = rs[lst];
    if (l == r) return;
    int mid = (l + r) >> 1;
    if (w <= mid) upd(ls[lst], l, mid, ls[rt], w, x);
    else upd(rs[lst], mid + 1, r, rs[rt], w, x);
}
int query(int l, int r, int k) {
    if (l == r) return l;
    int sum = 0, mid = (l + r) >> 1;
    for (int i = 1; i <= a; i ++) sum -= sz[ls[L[i]]];
    for (int i = 1; i <= b; i ++) sum += sz[ls[R[i]]];
    if (k <= sum) {
        for (int i = 1; i <= a; i ++) L[i] = ls[L[i]];
        for (int i = 1; i <= b; i ++) R[i] = ls[R[i]];
        return query(l, mid, k);
    }
    else {
        for (int i = 1; i <= a; i ++) L[i] = rs[L[i]];
        for (int i = 1; i <= b; i ++) R[i] = rs[R[i]];
        return query(mid + 1, r, k - sum);
    }
}
int main() {
    read(n); read(m);
    for (int i = 1; i <= n; i ++) {
        read(v[i]);
        disc[++ dtot] = v[i];
    }
    for (int i = 1; i <= m; i ++) {
        scanf("%s", opt);
        scanf("%d%d", &qus[i].x, &qus[i].y);
        if (opt[0] == 'Q') {
            scanf("%d", &qus[i].z);
            fg[i] = 1;
        }
        else disc[++ dtot] = qus[i].y;
    }
    sort(disc + 1, disc + 1 + dtot);
    dtot = unique(disc + 1, disc + 1 + dtot) - disc - 1;
    for (int i = 1; i <= n; i ++) {
        int t = find(v[i]);
        for (int j = i; j <= n; j += lowbit(j))
            upd(rt[j], 1, dtot, rt[j], t, 1);
    }
    for (int i = 1; i <= m; i ++) {
        if (fg[i]) {
            a = 0, b = 0; qus[i].x --;
            for (int j = qus[i].x; j; j -= lowbit(j))
                L[++ a] = rt[j];
            for (int j = qus[i].y; j; j -= lowbit(j))
                R[++ b] = rt[j];
            printf("%d\n", disc[query(1, dtot, qus[i].z)]);
        }
        else {
            int t = find(v[qus[i].x]);
            for (int j = qus[i].x; j <= n; j += lowbit(j))
                upd(rt[j], 1, dtot, rt[j], t, -1);
            v[qus[i].x] = qus[i].y;
            t = find(qus[i].y);
            for (int j = qus[i].x; j <= n; j += lowbit(j))
                upd(rt[j], 1, dtot, rt[j], t, 1);
        }
    }
    return 0;
}

关于整体二分,我不会,如果有时间那么我就把他补上。

[luogu2617][bzoj1901][Zju2112]Dynamic Rankings【树套树+树状数组+主席树】的更多相关文章

  1. bzoj1901: Zju2112 Dynamic Rankings(BIT套主席树)

    带修改的题主席树不记录前缀,只记录单点,用BIT统计前缀.  对于BIT上每一个点建一棵主席树,修改和询问的时候用BIT跑,在主席树上做就行了.  3k4人AC的题#256...应该不算慢 #incl ...

  2. [BZOJ1901]Zju2112 Dynamic Rankings

    [BZOJ1901]Zju2112 Dynamic Rankings 试题描述 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i ...

  3. BZOJ_1901_Zju2112 Dynamic Rankings_树状数组+主席树

    BZOJ_1901_Zju2112 Dynamic Rankings_树状数组+主席树 题意: 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i, ...

  4. zoj2112 树状数组+主席树 区间动第k大

    Dynamic Rankings Time Limit: 10000MS   Memory Limit: 32768KB   64bit IO Format: %lld & %llu Subm ...

  5. BZOJ_2120_数颜色_Set+树状数组+主席树

    BZOJ_2120_数颜色_Set+树状数组+主席树 Description 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L ...

  6. 【bzoj1146】[CTSC2008]网络管理Network 倍增LCA+dfs序+树状数组+主席树

    题目描述 M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高 ...

  7. 【bzoj3744】Gty的妹子序列 分块+树状数组+主席树

    题目描述 我早已习惯你不在身边, 人间四月天 寂寞断了弦. 回望身后蓝天, 跟再见说再见…… 某天,蒟蒻Autumn发现了从 Gty的妹子树(bzoj3720) 上掉落下来了许多妹子,他发现 她们排成 ...

  8. P1972 [SDOI2009]HH的项链[离线+树状数组/主席树/分块/模拟]

    题目背景 无 题目描述 HH 有一串由各种漂亮的贝壳组成的项链.HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH 不断地收集新的贝壳,因此,他的项链 ...

  9. BZOJ-1901 Zju2112 Dynamic Rankings 函数式线段树 套 树状数组+离线处理

    1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec Memory Limit: 128 MB Submit: 6058 Solved: 2521 [Su ...

随机推荐

  1. Spring.profile配合Jenkins发布War包,实现开发、测试和生产环境的按需切换

    前两篇不错 Spring.profile实现开发.测试和生产环境的配置和切换 - Strugglion - 博客园https://www.cnblogs.com/strugglion/p/709102 ...

  2. 【Python3练习题 016】 猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个。第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时,见只剩下一个桃子了。求第一天共摘了多少。

    这题得倒着推.第10天还没吃,就剩1个,说明第9天吃完一半再吃1个还剩1个,假设第9天还没吃之前有桃子p个,可得:p * 1/2 - 1 = 1,可得 p = 4.以此类推,即可手算出. 代码思路为: ...

  3. js-XMLHttpRequest 2级

    ###1. XMLHttpRquest 2级 1)   FormData 现代web应用中频繁使用的一项功能就死表单数据的序列化, XMLHttpRquest 2级为此定义了FormData类型 Fo ...

  4. 配置react-sass

    在配置react-sass时遇到很多坑其中 一条如果你的.scss文件失效 请一定要在fileloader之前配置该sass-loader 配置文件如下 基于你不熟悉webpack 容易出这个错误

  5. mysql5.7 的 user表的密码字段从 password 变成了 authentication_string

    来源: http://www.zhimengzhe.com/shujuku/other/267631.html 感觉还是挺坑的 自己没了解清楚 就动手 转帖一下 mark 一下. 1.首先停止正在运行 ...

  6. day84

    在建表写字端时,id可以不写,orm会自动创建 表模型如果不写主键,orm会自动创建一个主键 from django.db import models # Create your models her ...

  7. phpstorm显示页面不停的在indexing转圈中,并且文件名还一直在刷新

    打开 File下的 Invalidate Caches / Restart...下的 Invalidate and Restart. 便可以了 ......

  8. Struts2——通配符,Action Method_DMI

    Action wildcard 通配符(配置量降到最低) 使用通配符,就是为了配置简便,但是一定遵守“约定优于配置”原则,约定就是做项目之前最好事先与项目组的人或是自己规定好命名规则. 多个*  {1 ...

  9. docker学习笔记一

    知识点: 1)docker简介 2)docker安装,仓库配置 3)docker仓库镜像拉取,导出,导入,删除 4)docker容器操作,容器的创建,删除,运行,停止,日志查看等. 5)  docke ...

  10. flask 下载本地文件

    下载本地文件就是找到文件路径  调用flask自带的send_file(路径)下载, 并返回 flask: # 下载文件 from flask import send_file@task_mgm.ro ...