题目链接: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 + 树状数组套线段树】的更多相关文章

  1. BZOJ 3196 Tyvj 1730 二逼平衡树 ——树状数组套主席树

    [题目分析] 听说是树套树.(雾) 怒写树状数组套主席树,然后就Rank1了.23333 单点修改,区间查询+k大数查询=树状数组套主席树. [代码] #include <cstdio> ...

  2. bzoj3196 二逼平衡树 树状数组套线段树

    题目传送门 思路:树状数组套线段树模板题. 什么是树状数组套线段树,普通的树状数组每个点都是一个权值,而这里的树状数组每个点都是一颗权值线段树,我们用前缀差分的方法求得每个区间的各种信息, 其实关键就 ...

  3. bzoj 3110: [Zjoi2013]K大数查询 树状数组套线段树

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1384  Solved: 629[Submit][Stat ...

  4. [BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

    题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log^2 n). 线段树比树状数组麻 ...

  5. 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[ ...

  6. 洛谷P3380 【模板】二逼平衡树(树套树,树状数组,线段树)

    洛谷题目传送门 emm...题目名写了个平衡树,但是这道题的理论复杂度最优解应该还是树状数组套值域线段树吧. 就像dynamic ranking那样(蒟蒻的Sol,放一个link骗访问量233) 所有 ...

  7. [bzoj3196][Tyvj1730]二逼平衡树_树套树_位置线段树套非旋转Treap/树状数组套主席树/权值线段树套位置线段树

    二逼平衡树 bzoj-3196 Tyvj-1730 题目大意:请写出一个维护序列的数据结构支持:查询给定权值排名:查询区间k小值:单点修改:查询区间内定值前驱:查询区间内定值后继. 注释:$1\le ...

  8. [BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)

    [BZOJ 3295] [luogu 3157] [CQOI2011] 动态逆序对 (树状数组套权值线段树) 题面 给出一个长度为n的排列,每次操作删除一个数,求每次操作前排列逆序对的个数 分析 每次 ...

  9. luogu3380/bzoj3196 二逼平衡树 (树状数组套权值线段树)

    带修改区间K大值 这题有很多做法,我的做法是树状数组套权值线段树,修改查询的时候都是按着树状数组的规则找出那log(n)个线段树根,然后一起往下做 时空都是$O(nlog^2n)$的(如果离散化了的话 ...

随机推荐

  1. Cocos2d-x 3.1.1 学习日志9--一“上一下其乐无穷”游戏开发系列一

    下载地址:http://app.mi.com/search?keywords=%E4%B8%80%E4%B8%8A%E4%B8%80%E4%B8%8B%E5%85%B6%E4%B9%90%E6%97% ...

  2. register_globals(全局变量注册开关)

    register_globals,是php.ini文件里面的一个配置选项,接下来,我们可以通过例程来分析一下,当register_globals = on 与 register_globals = o ...

  3. react native web

    http://rawgit.com/taobaofed/react-web/master/pages/uiexplorer.html#/scene_1?_k=7vm99j

  4. iOS 9 关键字的简单使用

    前言: 在iOS 9 苹果推出了很多关键字, 目的其实很明确, 主要就是提高开发人员的效率, 有益于程序员之间的沟通与交流, 在开发中代码更加规范! 1. nullable 与 nonnull nul ...

  5. android之AlertDialog 点击其他区域自动消失

    遇到一个问题记录下来,在开发中使用了AlertDialog,想点击屏幕其他区域的时候让这个dialog消失,一开始不做任何设置,在小米手机可以正常显示,但是在三星中却有问题,后来发现少了一个属性: V ...

  6. JavaScript 应用开发 #3:应用的主视图

    目前为止,我们已经在应用里面,创建了表示数据的模型,表示数据列表的集合,组织模型显示的视图与模板.下面, 我们要想办法,去把模型的列表显示在应用的界面上.这样我们就可以再去为应用创建一个主要的视图,用 ...

  7. Mysql Join语法解析与性能分析详解

    一.Join语法概述 join 用于多表中字段之间的联系,语法如下: ... FROM table1 INNER|LEFT|RIGHT JOIN table2 ON conditiona table1 ...

  8. Chapter 5. The Gradle Wrapper 关于gradle wrapper

    Most tools require installation on your computer before you can use them. If the installation is eas ...

  9. day-9

    /* 考前第9天 区间*的线段树居然卡住了23333 明天再搞搞 今天针对考试复习了几个板子 手动堆都打了 实测比priority快 下午考试成了炮灰233333 晚上复习矩阵乘法 手推9*9矩阵 可 ...

  10. 文件夹IsShow字段为空

    IsShow为YesNo字段,默认值为Yes:在Library中新建一个文件的时候会给出默认值yes,但是新建一个文件夹的时候,默认为空,所以f.Item["IsShow"]为空, ...