[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)$的(如果离散化了的话 ...
随机推荐
- [TypeScript] Generating Definition Files
TypeScript allows you to generate definition files for your own libraries. This lesson shows you how ...
- COCOS2D-X 精灵创建随笔
CCSprite类中创建Sprite的方法都是静态的: static CCSprite* create ( ) 创建一个无图片显示的精灵,可随后用 setTexture 方法设置显示图片 stati ...
- [置顶] String StringBuffer StringBuilder的区别剖析
这是一道很常见的面试题目,至少我遇到过String/StringBuffer/StringBuilder的区别:String是不可变的对象(final)类型,每一次对String对象的更改均是生成一个 ...
- marquee 标签的使用详情
<marquee>标签,它是成对出现的标签,首标签<marquee>和尾标签</marquee>之间的内容就是滚动内容.<marquee>标签的属性主要 ...
- hdu2074java
叠筐 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submissi ...
- android开发之gridlayout使用入门
这个东东以前没怎么用过,今天研究了一下,不难,感觉只是在某些方面很好用. 记录下,做个计算器. <GridLayout xmlns:android="http://schemas.an ...
- JDK1.8聚合操作
在java8 JDK包含许多聚合操作(如平均值,总和,最小,最大,和计数),返回一个计算流stream的聚合结果.这些聚合操作被称为聚合操作.JDK除返回单个值的聚合操作外,还有很多聚合操作返回一个c ...
- CS0016: 未能写入输出文件“c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\d29b5393\123c3a1c\App_Code.odl3w4o6.dll”--“拒绝访问。 ”
IIS部署网站或者Webservice时,出现以下问题: CS0016: 未能写入输出文件“c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Tempor ...
- 在Abp框架中使用Mysql数据库的方法以及相关问题小记
最近发现了一款DDD的框架 看起来不错,据说挺流弊的 刚好最近要弄点小东西,拿来试试也不错 苦于穷逼买不起高配服务器,只好装mysql数据库了 下面说下如何在该框架下使用Mysql数据库 打开项目后, ...
- a标签的简单用法
1.href="#"的作用:页面中有滚动,可以直接回到顶部. <a href="#">回到最顶端</a> 2.href="ur ...