博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
整体二分专题
阅读量:4545 次
发布时间:2019-06-08

本文共 3522 字,大约阅读时间需要 11 分钟。

整体二分专题

A - K-th Number [POJ - 2104 ]

\(1 <= n <= 100 000, 1 <= m <= 5 000\), 给出数组\(a[1..n](\leq1e9)\)

然后有\(m\)个询问, 每次询问\(Q(l,r,k)\)\(a[l..r]\)之间从小到大第\(k\)个的数

B - Dynamic Rankings [ZOJ-2112]

\(1 <= N <= 50,000 ~~~~ 1 <= M <= 10,000\), 给出数组\(a[1..n](\leq1e9)\)

然后有\(m\)个操作:

  • \(C~i~t\)\(a[i]\)改为\(t\)

  • \(Q~i~j~k\)\(a[l..r]\)之间从小到大第​k个的数

C - K大数查询 [HYSBZ - 3110]

\(N\)个位置,\(M\)个操作。操作有两种,每次操作如果是\(1~a~b~c\)的形式表示在第a个位置到第\(b\)个位置,每个位置加入一个数\(c\)

如果是\(2~a~b~c\)形式,表示询问从第\(a\)个位置到第\(b\)个位置,第\(C\)大的数是多少。

【样例说明】

第一个操作 后位置 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操作中\(c<=Maxlongint\)

思路

A

将数组数值和询问一起放入操作序列\(a[]\)

\(solve(x, y, l, r)\)代表操作编号在\([x,y]\)间的询问的答案在\([l,r]\)之间, 并且当前\([x,y]\)间的询问只能由\([x,y]\)之间的数值贡献​

\(solve()\)中:

  • \(mid = (l + r) >> 1\), 假设询问的答案为\(mid\),那么要检查\(\leq mid\)的个数符不符合每个询问要求的个数
  • 如果这个操作是数组中的数, 则
    • \(\leq mid\), 则放入\(a_l[]\)中,这部分对之后的询问有贡献,将位置加入树状数组
    • 否则放入\(a_r[]\)
  • 否则就是一个询问, 调用树状数组,求\(\leq mid\)的个数
    • 如果\(\geq\)需要的个数,那么实际答案比\(mid\)小(等于), 放入\(a_l[]\)
    • 否则实际答案比\(mid\)大,减去现在贡献, 放入\(a_r[]\)

\(和放回a_l[]和a_r[]放回a[]\)中, \(区间区间solve(l区间,l,mid), solve(r区间, mid+1,r)\)

如果\(l==r\)则区间内的询问答案都确定了

到边界就return

#include 
#include
#include
#include
#include
using namespace std;typedef long long LL;const int MAXN = 1e5 + 10;const int INF = 1e9 + 10;inline int in(){ int x = 0, flag = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') flag = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar(); return x * flag;}int n, m, tot;struct Fenwick{ int val[MAXN]; void upd(int x, int v) { for (int i = x; i <= 100000; i += (i & (-i))) val[i] += v; } int qry(int x) { int ret = 0; for (int i = x; i > 0; i &= (i - 1)) ret += val[i]; return ret; }} T;struct Node{ int v, l, r, p, typ, id;} a[MAXN << 1], al[MAXN << 1], ar[MAXN << 1];int an[MAXN];void solve(int x, int y, int l, int r){ if (l > r || x >= y) return ; if (l == r) { for (int i = x; i <= y; i ++) if (a[i].typ == 1) an[a[i].id] = l; return; } int mid = (l + r) >> 1; int cntl = 0, cntr = 0; for (int i = x; i <= y; i ++) { if (a[i].typ == 0) { if (a[i].v <= mid) al[++cntl] = a[i], T.upd(a[i].id, 1); else ar[++cntr] = a[i]; } else { int val = T.qry(a[i].r) - T.qry(a[i].l - 1); if (a[i].p <= val) al[++cntl] = a[i]; else a[i].p -= val, ar[++cntr] = a[i]; } } for (int i = x; i <= y; i ++) if (a[i].typ == 0 && a[i].v <= mid) T.upd(a[i].id, -1); for (int i = 1; i <= cntl; i ++) a[x + i - 1] = al[i]; for (int i = 1; i <= cntr; i ++) a[x + cntl + i - 1] = ar[i]; solve(x, x + cntl - 1, l, mid); solve(y - cntr + 1, y, mid + 1, r);}int main(){ n = in(); m = in(); for (int i = 1; i <= n; i ++) { a[++ tot].v = in(); a[tot].typ = 0; a[tot].id = i; } for (int i = 1; i <= m; i ++) { a[++ tot] = (Node) {0, in(), in(), in(), 1, i }; } solve(1, tot, -INF, INF); for (int i = 1; i <= m; i ++) printf("%d\n", an[i]); return 0;}

B

小改改(思考如何转化change)

C

小改改(思考如何处理区间而非前缀)

转载于:https://www.cnblogs.com/ikihsiguoyr/p/10561307.html

你可能感兴趣的文章
《学习之道》第三章学习方法12批评使我们更优秀
查看>>
猫眼首页
查看>>
java面试题之数据基本类型各占几个字节
查看>>
设计模式(总纲)
查看>>
线程池技术
查看>>
http后台json解析实例
查看>>
iOS中延时执行方法的比较和汇总
查看>>
1284 2 3 5 7的倍数
查看>>
php 手记
查看>>
设计模式-注册树模式
查看>>
Unity基本API总览
查看>>
如何将一段文本编译成C#内存程序的过程
查看>>
PAT——1070. 结绳
查看>>
【23.33%】【codeforces 664C】International Olympiad
查看>>
java-网络编程-使用URLDecoder和URLEncoder
查看>>
最短路之dijkstra算法
查看>>
SHDP--Working With HBase (二)之HBase JDBC驱动Phoenix与SpringJDBCTemplate的集成
查看>>
Lua语法基础(一)
查看>>
.Net Core2.*学习手册
查看>>
实验一、命令解释程序的编写实验
查看>>