[BZOJ 3196] 213平衡树 【线段树套set + 树状数组套线段树】
题目链接:BZOJ - 3196
题目分析
区间Kth和区间Rank用树状数组套线段树实现,区间前驱后继用线段树套set实现。
为了节省空间,需要离线,先离散化,这样需要的数组大小可以小一些,可以卡过128MB = =
嗯就是这样,代码长度= =我写了260行......Debug了n小时= =
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <map>
using namespace std; const int MaxN = 50000 + 5, MaxM = 50000 + 5, MN = 100000 + 15, INF = 999999999, MaxNode = 8000000 + 15; int n, m, Index, Used_Index, Top, Hash_Index;
int A[MaxN], Root[MaxN], T[MaxNode], Son[MaxNode][2], U[MaxN], C[MaxN], Que[MaxN + MaxM], TR[MaxN + MaxM]; struct Query
{
int f, L, R, k, Num, Pos;
} Q[MaxM]; map<int, int> M; multiset<int> S[MaxN * 4];
multiset<int>::iterator It; inline int gmin(int a, int b) {return a < b ? a : b;}
inline int gmax(int a, int b) {return a > b ? a : b;} void Add(int &x, int s, int t, int Pos, int Num)
{
if (x == 0) x = ++Index;
T[x] += Num;
if (s == t) return;
int m = (s + t) >> 1;
if (Pos <= m) Add(Son[x][0], s, m, Pos, Num);
else Add(Son[x][1], m + 1, t, Pos, Num);
} void Change(int x, int Pos, int Num)
{
for (int i = x; i <= n; i += i & -i)
Add(Root[i], 0, MN, Pos, Num);
} void Add_S(int x, int s, int t, int Pos, int Num)
{
S[x].insert(Num);
if (s == t) return;
int m = (s + t) >> 1;
if (Pos <= m) Add_S(x << 1, s, m, Pos, Num);
else Add_S(x << 1 | 1, m + 1, t, Pos, Num);
} void Del_S(int x, int s, int t, int Pos, int Num)
{
S[x].erase(S[x].find(Num));
if (s == t) return;
int m = (s + t) >> 1;
if (Pos <= m) Del_S(x << 1, s, m, Pos, Num);
else Del_S(x << 1 | 1, m + 1, t, Pos, Num);
} void Init_U(int x)
{
for (int i = x; i; i -= i & -i)
U[i] = Root[i];
} void Turn(int x, int f)
{
for (int i = x; i; i -= i & -i)
{
if (C[i] == Used_Index) break;
C[i] = Used_Index;
U[i] = Son[U[i]][f];
}
} int Get_LSum(int x)
{
int ret = 0;
for (int i = x; i; i -= i & -i)
ret += T[Son[U[i]][0]];
return ret;
} int Before(int x, int s, int t, int l, int r, int Num)
{
int ret;
if (l <= s && r >= t)
{
It = S[x].end();
It--;
if (*It < Num) return *It;
It = S[x].begin();
if (*It >= Num) return -INF;
It = S[x].lower_bound(Num);
It--;
return *It;
}
int m = (s + t) >> 1;
ret = -INF;
if (l <= m) ret = gmax(ret, Before(x << 1, s, m, l, r, Num));
if (r >= m + 1) ret = gmax(ret, Before(x << 1 | 1, m + 1, t, l, r, Num));
return ret;
} int After(int x, int s, int t, int l, int r, int Num)
{
int ret;
if (l <= s && r >= t)
{
It = S[x].upper_bound(Num);
if (It == S[x].end()) return INF;
else return *It;
}
int m = (s + t) >> 1;
ret = INF;
if (l <= m) ret = gmin(ret, After(x << 1, s, m, l, r, Num));
if (r >= m + 1) ret = gmin(ret, After(x << 1 | 1, m + 1, t, l, r, Num));
return ret;
} int main()
{
scanf("%d%d", &n, &m);
Top = 0; Index = 0;
for (int i = 1; i <= n; ++i)
{
scanf("%d", &A[i]);
Que[++Top] = A[i];
}
for (int i = 1; i <= m; ++i)
{
scanf("%d", &Q[i].f);
switch (Q[i].f)
{
case 1 :
scanf("%d%d%d", &Q[i].L, &Q[i].R, &Q[i].Num);
break;
case 2 :
scanf("%d%d%d", &Q[i].L, &Q[i].R, &Q[i].k);
break;
case 3 :
scanf("%d%d", &Q[i].Pos, &Q[i].Num);
break;
case 4 :
scanf("%d%d%d", &Q[i].L, &Q[i].R, &Q[i].Num);
break;
case 5 :
scanf("%d%d%d", &Q[i].L, &Q[i].R, &Q[i].Num);
break;
}
if (Q[i].f != 2) Que[++Top] = Q[i].Num;
}
sort(Que + 1, Que + Top + 1);
Hash_Index = 0;
for (int i = 1; i <= Top; ++i)
{
if (i > 1 && Que[i] == Que[i - 1]) continue;
M[Que[i]] = ++Hash_Index;
TR[Hash_Index] = Que[i];
}
for (int i = 1; i <= n; ++i)
{
A[i] = M[A[i]];
Change(i, A[i], 1);
Add_S(1, 1, n, i, A[i]);
}
int L, R, Pos, Num, k, Temp, l, r, mid;
for (int i = 1; i <= m; ++i)
{
if (Q[i].f != 2) Q[i].Num = M[Q[i].Num];
switch (Q[i].f)
{
case 1 :
L = Q[i].L; R = Q[i].R; Num = Q[i].Num;
Used_Index = 0;
Init_U(L - 1);
Init_U(R);
Temp = 0;
l = 0; r = MN;
while (l < r)
{
++Used_Index;
mid = (l + r) >> 1;
if (Num <= mid)
{
r = mid;
Turn(L - 1, 0);
Turn(R, 0);
}
else
{
Temp += Get_LSum(R) - Get_LSum(L - 1);
l = mid + 1;
Turn(L - 1, 1);
Turn(R, 1);
}
}
printf("%d\n", Temp + 1);
break; case 2 :
L = Q[i].L; R = Q[i].R; k = Q[i].k;
Init_U(L - 1);
Init_U(R);
Used_Index = 0;
Temp = 0;
l = 0; r = MN;
while (l < r)
{
++Used_Index;
mid = (l + r) >> 1;
Temp = Get_LSum(R) - Get_LSum(L - 1);
if (Temp >= k)
{
r = mid;
Turn(L - 1, 0);
Turn(R, 0);
}
else
{
l = mid + 1;
Turn(L - 1, 1);
Turn(R, 1);
k -= Temp;
}
}
printf("%d\n", TR[l]);
break; case 3 :
Pos = Q[i].Pos; Num = Q[i].Num;
Change(Pos, A[Pos], -1);
Del_S(1, 1, n, Pos, A[Pos]);
A[Pos] = Num;
Change(Pos, Num, 1);
Add_S(1, 1, n, Pos, Num);
break; case 4 :
L = Q[i].L; R = Q[i].R; Num = Q[i].Num;
printf("%d\n", TR[Before(1, 1, n, L, R, Num)]);
break; case 5 :
L = Q[i].L; R = Q[i].R; Num = Q[i].Num;
printf("%d\n", TR[After(1, 1, n, L, R, Num)]);
break;
}
}
return 0;
}
[BZOJ 3196] 213平衡树 【线段树套set + 树状数组套线段树】的更多相关文章
- BZOJ 3196 Tyvj 1730 二逼平衡树 ——树状数组套主席树
[题目分析] 听说是树套树.(雾) 怒写树状数组套主席树,然后就Rank1了.23333 单点修改,区间查询+k大数查询=树状数组套主席树. [代码] #include <cstdio> ...
- bzoj3196 二逼平衡树 树状数组套线段树
题目传送门 思路:树状数组套线段树模板题. 什么是树状数组套线段树,普通的树状数组每个点都是一个权值,而这里的树状数组每个点都是一颗权值线段树,我们用前缀差分的方法求得每个区间的各种信息, 其实关键就 ...
- bzoj 3110: [Zjoi2013]K大数查询 树状数组套线段树
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1384 Solved: 629[Submit][Stat ...
- [BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】
题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log^2 n). 线段树比树状数组麻 ...
- BZOJ.4553.[HEOI2016&TJOI2016]序列(DP 树状数组套线段树/二维线段树(MLE) 动态开点)
题目链接:BZOJ 洛谷 \(O(n^2)\)DP很好写,对于当前的i从之前满足条件的j中选一个最大值,\(dp[i]=d[j]+1\) for(int j=1; j<i; ++j) if(a[ ...
- 洛谷P3380 【模板】二逼平衡树(树套树,树状数组,线段树)
洛谷题目传送门 emm...题目名写了个平衡树,但是这道题的理论复杂度最优解应该还是树状数组套值域线段树吧. 就像dynamic ranking那样(蒟蒻的Sol,放一个link骗访问量233) 所有 ...
- [bzoj3196][Tyvj1730]二逼平衡树_树套树_位置线段树套非旋转Treap/树状数组套主席树/权值线段树套位置线段树
二逼平衡树 bzoj-3196 Tyvj-1730 题目大意:请写出一个维护序列的数据结构支持:查询给定权值排名:查询区间k小值:单点修改:查询区间内定值前驱:查询区间内定值后继. 注释:$1\le ...
- [BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)
[BZOJ 3295] [luogu 3157] [CQOI2011] 动态逆序对 (树状数组套权值线段树) 题面 给出一个长度为n的排列,每次操作删除一个数,求每次操作前排列逆序对的个数 分析 每次 ...
- luogu3380/bzoj3196 二逼平衡树 (树状数组套权值线段树)
带修改区间K大值 这题有很多做法,我的做法是树状数组套权值线段树,修改查询的时候都是按着树状数组的规则找出那log(n)个线段树根,然后一起往下做 时空都是$O(nlog^2n)$的(如果离散化了的话 ...
随机推荐
- Python 基础学习
http://www.cnblogs.com/Wxtrkbc/p/5486253.html
- apache日志介绍
apache日志介绍: 通用日志格式: CommonLogFormat 组合日志格式: CombinedLogFormat 例如: <VirtualHost *: ...
- Jquery Ajax方法传递json到action
ajax向后台传入json需要设置option,如下 contentType:'application/json' data:Json.Stringify(jsObj) 后台处理复杂json对象(不知 ...
- PHP制作简单的日历
在这里分享一个PHP制作的日历 <?php //万年历if($_GET['year']){$year = $_GET['year'];}else{$year = date("Y&quo ...
- [弹出消息] C#MessageBox帮助类 (转载)
点击下载 MessageBox.rar 主要功能如下所示1.显示消息提示对话框 2.控件点击 消息确认提示框 3.显示消息提示对话框,并进行页面跳转 4.输出自定义脚本信息 /// <summa ...
- 如何下载到最新的版本的Oracle Database
其实这不是一个很困难的事情,但是发现好多同学都不知道,其实只需直接访问Oracle的官网就可以找到,鉴于Oracle经常改到下载面也我这里直接粘贴下载地址 http://www.oracle.com/ ...
- .NET下的加密解密大全(3):非对称加密
本博文列出了.NET下常用的非对称加密算法,并将它们制作成小DEMO,希望能对大家有所帮助. RSA[csharp]static string EnRSA(string data,string pub ...
- js setInterval和clearInterval 的使用
setInterval(函数名, 时间); 函数名:不需要加括号: 时间:单位是毫秒: 例子: var inter= setInterval(searchTasksByCnd, 10 * 100 ...
- (九)Struts2 防重复提交
所有的学习我们必须先搭建好Struts2的环境(1.导入对应的jar包,2.web.xml,3.struts.xml) 第一节:重复提交示例演示 struts.xml <?xml version ...
- OC - 15.NSURLSession与NSURLSessionTask
简介 NSURLSession也能完成网络请求 NSURLConnection在iOS9中不推荐使用,NSURLSession是iOS9中推荐使用的网络请求方式 NSURLSession需要与NSUR ...