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

BIT+(可持久化)权值线段树, 用到了BIT的差分技巧. 时间复杂度O(Nlog^2(N))

-----------------------------------------------------------------------------------------

#include<cstdio>

#include<cctype>

#include<cstring>

#include<algorithm>

using namespace std;

#define H(x) (lower_bound(H, H + n, x) - H + 1)

#define lb(x) ((x) & -(x))

const int maxn = 50009;

int N, Q, Pos;

int H[maxn], n;

inline int getint() {

char c = getchar();

int ret = 0, f = 1;

for(; !isdigit(c); c = getchar()) if(c == ‘-‘) f = 0;

for(; isdigit(c); c = getchar()) ret = ret * 10 - ‘0‘ + c;

return f ? ret : -ret;

}

struct O {

int t, l, r, v;

inline void Read() {

t = getint(), l = getint(), r = getint(), v = getint();

}

} o[maxn];

struct Node {

Node *lc, *rc;

int v;

} pool[maxn * 400], *pt, *Null, *A[maxn], *B[maxn];

void Init_sgt() {

(pt = pool)->v = 0;

pt->lc = pt->rc = pt;

Null = pt++;

}

Node* Modify(Node* t, int l, int r, int ad) {

Node* p = pt++;

p->v = t->v + ad;

if(l != r) {

int m = (l + r) >> 1;

if(Pos <= m) {

p->lc = Modify(t->lc, l, m, ad);

p->rc = t->rc;

} else {

p->lc = t->lc;

p->rc = Modify(t->rc, m + 1, r, ad);

}

}

return p;

}

Node *L0[20], *L1[20], *L[20];

Node *R0[20], *R1[20];

void Work() {

Init_sgt();

int ln, rn, sn;

for(int i = 0; i <= N; i++) A[i] = B[i] = Null;

for(int i = 0; i < Q; i++) if(o[i].t == 1) {

Pos = H(o[i].v);

for(int x = o[i].l; x <= N; x += lb(x)) {

A[x] = Modify(A[x], 1, n, 1);

B[x] = Modify(B[x], 1, n, o[i].l - 1);

}

for(int x = o[i].r + 1; x <= N; x += lb(x)) {

A[x] = Modify(A[x], 1, n, -1);

B[x] = Modify(B[x], 1, n, -o[i].r);

}

} else {

ln = rn = sn = 0;

for(int x = o[i].l; x; x -= lb(x)) L[sn++] = A[x];

for(int x = o[i].l; x; x -= lb(x))

L0[ln] = A[x], R1[ln++] = B[x];

for(int x = o[i].r; x; x -= lb(x))

R0[rn] = A[x], L1[rn++] = B[x];

int l = 1, r = n, len = o[i].r - o[i].l + 1;

while(l < r) {

int m = (l + r) >> 1, cnt = 0;

for(int x = 0; x < sn; x++) cnt += L[x]->rc->v * len;

for(int x = 0; x < ln; x++)

cnt += R1[x]->rc->v - o[i].r * L0[x]->rc->v;

for(int x = 0; x < rn; x++)

cnt += o[i].r * R0[x]->rc->v - L1[x]->rc->v;

if(cnt >= o[i].v) {

for(int x = 0; x < sn; x++) L[x] = L[x]->rc;

for(int x = 0; x < ln; x++)

R1[x] = R1[x]->rc, L0[x] = L0[x]->rc;

for(int x = 0; x < rn; x++)

R0[x] = R0[x]->rc, L1[x] = L1[x]->rc;

l = m + 1;

} else {

o[i].v -= cnt;

for(int x = 0; x < sn; x++) L[x] = L[x]->lc;

for(int x = 0; x < ln; x++)

R1[x] = R1[x]->lc, L0[x] = L0[x]->lc;

for(int x = 0; x < rn; x++)

R0[x] = R0[x]->lc, L1[x] = L1[x]->lc;

r = m;

}

}

printf("%d\n", H[l - 1]);

}

}

void Init() {

N = getint(), Q = getint();

n = 0;

for(int i = 0; i < Q; i++) {

o[i].Read();

if(o[i].t == 1) H[n++] = o[i].v;

}

sort(H, H + n);

n = unique(H, H + n) - H;

}

int main() {

Init();

Work();

return 0;

}

-----------------------------------------------------------------------------------------

3110: [Zjoi2013]K大数查询

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 2921  Solved: 1247
[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 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

【样例说明】

第一个操作 后位置 1 的数只有 1 , 位置 2 的数也只有 1 。 第二个操作 后位置 1

的数有 1 、 2 ,位置 2 的数也有 1 、 2 。 第三次询问 位置 1 到位置 1 第 2 大的数 是

1 。 第四次询问 位置 1 到位置 1 第 1 大的数是 2 。 第五次询问 位置 1 到位置 2 第 3

大的数是 1 。‍

N,M<=50000,N,M<=50000

a<=b<=N

1操作中abs(c)<=N

2操作中abs(c)<=Maxlongint

Source

时间: 2024-10-22 07:01:21

BZOJ 3110: [Zjoi2013]K大数查询( 树状数组套主席树 )的相关文章

树套树专题——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

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在区间内的后继(后继定义为

[COGS257]动态排名系统 树状数组套主席树

257. 动态排名系统 时间限制:5 s   内存限制:512 MB [问题描述]给定一个长度为N的已知序列A[i](1<=i<=N),要求维护这个序列,能够支持以下两种操作:1.查询A[i],A[i+1],A[i+2],...,A[j](1<=i<=j<=N)中,升序排列后排名第k的数.2.修改A[i]的值为j.所谓排名第k,指一些数按照升序排列后,第k位的数.例如序列{6,1,9,6,6},排名第3的数是6,排名第5的数是9.[输入格式]第一行包含一个整数D(0<=

【BZOJ1901】Dynamic Rankings,树状数组套主席树

Time:2016.05.09 Author:xiaoyimi 转载注明出处谢谢 传送门(权限) 题面 1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec Memory Limit: 128 MB Submit: 6678 Solved: 2777 [Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a

关于树状数组套主席树的一些博客

哇仿佛磕了几百年啊; 废话不多说,以下是帮助很大的一些blog: ZOJ 2112 Dynamic Rankings (动态第k大,树状数组套主席树) 主席树全纪录(这个很好) 主席树乱讲(没啥关系,不过有些题目可以刷??) 随笔分类 - 数据结构---主席树(同上) 原文地址:https://www.cnblogs.com/wwtt/p/10099695.html

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

【树状数组套主席树】带修改区间K大数

P2617 Dynamic Rankings 题目描述给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题.你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令. 对于每一个询问指令,你必须输出正确的回答. 输入输出格式输入格

zoj 2112 Dynamic Rankings(树状数组套主席树)

题意:对于一段区间,每次求[l,r]的第k大,存在单点修改操作: 思路: 学习主席树参考: http://blog.csdn.net/wjf_wzzc/article/details/24560117(各种形式) http://blog.csdn.net/bossup/article/details/31921235(推荐) http://blog.csdn.net/xiaofengcanyuexj/article/details/25553521?utm_source=tuicool(图解)