acdreamOJ 1108分块算法
2014-09-30 13:50
435 查看
/* 分块算法 1.把所有的询问存起来 2.根据区间左端点分块,尽可能平均。 3.在同一个块内的,右端点升序,从而使右端点的移动一直向右,为O(n),而左端点因为在一个块内,每次移动最多是logn。 所以总的时间复杂度是 O(m * logn + n) 4.同理,即使是不同的块,因为均分使得一个块内最多也就是logn个,所以时间复杂度不变。 */ #include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> using namespace std; const int N = 1e5 + 111; const int Q = 350; int a , l , r , k , id , tot , fre , ans ; int cmp(int a, int b) { if (l[a] / Q == l[b] / Q) return r[a] < r[b]; return l[a] < l[b]; } int find(int x) { int l = 1, r = 1e5; int ret = 1; while (l <= r) { int m = (l + r) >> 1; if (fre[m] >= x) ret = m, l = m + 1; else r = m - 1; } return ret; } int main() { int T; scanf("%d", &T); while (T--) { int n, m; scanf("%d %d", &n, &m); for (int i = 1; i <= n; ++i) scanf("%d", &a[i]); for (int i = 1; i <= m; ++i) { scanf("%d %d %d", &l[i], &r[i], &k[i]); id[i] = i; } sort(id + 1, id + m + 1, cmp); int nowL = 1, nowR = 0; memset(fre, 0, sizeof(fre)); memset(tot, 0, sizeof(tot)); for (int i = 1; i <= m; ++i) { int ID = id[i]; int L = l[ID]; int R = r[ID]; while (nowL > L) ++fre[++tot[a[--nowL]]]; while (nowR < R) ++fre[++tot[a[++nowR]]]; while (nowL < L) fre[tot[a[nowL++]]--]--; while (nowR > R) fre[tot[a[nowR--]]--]--; ans[ID] = find(k[ID]); } for (int i = 1; i <= m; ++i) printf("%d\n", ans[i]); } return 0; }
相关文章推荐
- Acdreamoj1115(数学思维称号)
- AC dreamoj 1011 树状数组+hash维护字符串的前缀和
- ACdream OJ 1099 瑶瑶的第K大
- ACdreamoj 1011(树状数组维护字符串hash前缀和)
- ACdreamoj 1011(树状数组维护字符串hash前缀和)
- ACdream OJ 1153 (k-GCD)
- acdream oj 1101 瑶瑶想要玩滑梯
- ACdreamoj(1105)模拟题
- AcDream OJ 1127 Base Station
- acdream oj 1105 瑶瑶带你玩激光坦克
- ACdreamoj(1105)模拟题
- ACdreamOJ 1135 Collatz
- acdreamoj 1106 游泳水平有限的瑶瑶
- acdreamoj 1211 有上下界的网络流
- acdreamoj1112 sg函数
- 【ACdream OJ 1099 - 瑶瑶的第K大 (输入优化+手写O(n)快排)】
- ACdream OJ - 1061 && 1062 && 1098 && 1099
- acdreamoj 1064 完美数
- acdream oj 1211 有上下界的网络流
- acdreamOJ 1236 求无向图的桥