「ZJOI2013」K大数查询

「ZJOI2013」K大数查询

传送门
整体二分,修改的时候用线段树代替树状数组即可。
参考代码:

#include <cstdio>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
template < class T > inline void read(T& s) {
    s = 0; int f = 0; char c = getchar();
    while ('0' > c || c > '9') f |= c == '-', c = getchar();
    while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
    s = f ? -s : s;
}

typedef long long LL;
const int _ = 5e4 + 5;

int n, m, q, res[_]; LL sum[_ << 2]; int tag[_ << 2];
struct node { int opt, l, r; LL c; int id; } t[_], tt1[_], tt2[_];

inline int lc(int p) { return p << 1; }

inline int rc(int p) { return p << 1 | 1; }

inline void pushup(int p) { sum[p] = sum[lc(p)] + sum[rc(p)]; }

inline void f(int p, int l, int r, int v) { sum[p] += 1ll * v * (r - l + 1), tag[p] += v; }

inline void pushdown(int p, int l, int r, int mid)
{ if (tag[p]) f(lc(p), l, mid, tag[p]), f(rc(p), mid + 1, r, tag[p]), tag[p] = 0; }

inline void update(int ql, int qr, int v, int p = 1, int l = 1, int r = n) {
    if (ql <= l && r <= qr) return f(p, l, r, v);
    int mid = (l + r) >> 1;
    pushdown(p, l, r, mid);
    if (ql <= mid) update(ql, qr, v, lc(p), l, mid);
    if (qr > mid) update(ql, qr, v, rc(p), mid + 1, r);
    pushup(p);
}

inline LL query(int ql, int qr, int p = 1, int l = 1, int r = n) {
    if (ql <= l && r <= qr) return sum[p];
    int mid = (l + r) >> 1; LL res = 0;
    pushdown(p, l, r, mid);
    if (ql <= mid) res += query(ql, qr, lc(p), l, mid);
    if (qr > mid) res += query(ql, qr, rc(p), mid + 1, r);
    return res;
}

inline void solve(int ql, int qr, int l, int r) {
    if (ql > qr || l > r) return ;
    if (l == r) { for (rg int i = ql; i <= qr; ++i) if (t[i].opt == 2) res[t[i].id] = l; return ; }
    int mid = (l + r) >> 1, p1 = 0, p2 = 0;
    for (rg int i = ql; i <= qr; ++i) {
        if (t[i].opt == 1) {
            if (t[i].c <= mid) tt1[++p1] = t[i]; else update(t[i].l, t[i].r, 1), tt2[++p2] = t[i];
        } else {
            LL cnt = query(t[i].l, t[i].r);
            if (cnt < t[i].c) t[i].c -= cnt, tt1[++p1] = t[i]; else tt2[++p2] = t[i];
        }
    }
    for (rg int i = 1; i <= p2; ++i) if (tt2[i].opt == 1) update(tt2[i].l, tt2[i].r, -1);
    for (rg int i = 1; i <= p1; ++i) t[ql + i - 1] = tt1[i];
    for (rg int i = 1; i <= p2; ++i) t[ql + p1 + i - 1] = tt2[i];
    solve(ql, ql + p1 - 1, l, mid), solve(ql + p1, qr, mid + 1, r);
}

int main() {
    read(n), read(m);
    for (rg int i = 1; i <= m; ++i)
        read(t[i].opt), read(t[i].l), read(t[i].r), read(t[i].c), t[i].id = t[i].opt == 2 ? ++q : 0;
    solve(1, m, 0, n);
    for (rg int i = 1; i <= q; ++i) printf("%d\n", res[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/zsbzsb/p/12231706.html

时间: 2024-10-10 10:06:03

「ZJOI2013」K大数查询的相关文章

【ZJOI2013】k大数查询 BZOJ 3110

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 c Output 输出每个询问的结果 Sample Input 2 5 1 1 2 1 1 1 2 2 2 1 1 2 2 1 1 1 2 1 2 3 Sample Output 1 2 1 HINT

【BZOJ3110】【Zjoi2013】K大数查询 树套树 权值线段树套区间线段树

#include <stdio.h> int main() { puts("转载请注明出处谢谢"); puts("http://blog.csdn.net/vmurder/article/details/43020009"); } 题解: 外层权值线段树,内层区间线段树可解. 权值都是1~n,就不用离散化了. 我写了标记永久化. 其它心得神马的: 天生对树形数据结构无爱. 第一次写树套树,终于知道是怎么回事了. (只针对本题) 就是外层每个点都表示了一段

BZOJ 3110: [Zjoi2013]K大数查询( 树状数组套主席树 )

BIT+(可持久化)权值线段树, 用到了BIT的差分技巧. 时间复杂度O(Nlog^2(N)) ----------------------------------------------------------------------------------------- #include<cstdio> #include<cctype> #include<cstring> #include<algorithm> using namespace std;

BZOJ 3110: [Zjoi2013]K大数查询 [树套树]

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

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

【BZOJ3110】[Zjoi2013]K大数查询 树套树

[BZOJ3110][Zjoi2013]K大数查询 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 c Output 输出每个询问的结果 Sample Input 2 5 1 1 2 1 1 1 2 2 2 1 1 2 2 1 1 1 2 1 2 3

树套树专题——bzoj 3110: [Zjoi2013] K大数查询 &amp; 3236 [Ahoi2013] 作业 题解

[原题1] 3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 978  Solved: 476 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 c Outpu

洛谷 P3332 [ZJOI2013]K大数查询 || bzoj3110

用树套树就很麻烦,用整体二分就成了裸题.... 错误: 1.尝试线段树套平衡树,码农,而且n*log^3(n)慢慢卡反正我觉得卡不过去 2.线段树pushdown写错...加法tag对于区间和的更新应该要乘上区间长度的 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 typedef long long LL; 6 struct Q 7 { 8 LL

[ZJOI2013]K大数查询——整体二分

新科技:整体二分 它能解决的典型问题:带修改区间第\(k\)大 大概的做法是这样的:我们一次二分一个值\(mid\),然后依据操作的答案与\(mid\)的大小关系把操作分别划到两边,然后递归下去.也就是相当于二分的是所有询问的答案 感觉其实这个跟在权值线段树上二分一个效果,只是用离线的方式替代掉了那一层权值线段树而已 计算可得复杂度为\(O(nlog^2n)\)(由主定理,\(T(n)=2T(n/2)+O(nlogn)=O(nlog^2n)\)) 拿线段树或者树状数组维护都行 板子题是这一道K大