您的位置:首页 > 其它

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;
}



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: