您的位置:首页 > 其它

HDU 3727 Jewel(划分树 + 二分)

2015-10-28 15:28 459 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3727

题意:有四类操作:

1.insert x 在当前序列最后插入数x

2.query_1 s t k 查询序列[s, t]内第k小的数

3.query_2 x 查询数x的rank

4.query_3 x 查询[1, len]内第k小的数,len为当前序列的长度

思路:

因为每次插入数都是在最后,故考虑离线操作,对于1,3操作都可以记录查询范围然后划分树求解,对于2操作可以通过二分该rank + 划分树求值判断

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <climits>
#include <functional>
#include <deque>
#include <ctime>

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#pragma comment(linker, "/STACK:102400000,102400000")

using namespace std;

const int maxn = 100010;

vector <int> g[maxn];

int vis[maxn], cnt;

int tree[20][maxn];//表示每层每个位置的值
int sorted[maxn];//已经排序好的数
int toleft[20][maxn];//toleft[p][i]表示第i层从1到i有数分入左边

void build(int l, int r, int dep)
{
if (l == r) return;
int mid = (l + r) >> 1;
int same = mid - l + 1;
for (int i = l; i <= r; i++)
if (tree[dep][i] < sorted[mid])
same--;
int lpos = l;
int rpos = mid + 1;
for (int i = l; i <= r; i++)
{
if (tree[dep][i] < sorted[mid])
tree[dep + 1][lpos++] = tree[dep][i];
else if (tree[dep][i] == sorted[mid] && same > 0)
{
tree[dep + 1][lpos++] = tree[dep][i];
same--;
}
else
tree[dep + 1][rpos++] = tree[dep][i];
toleft[dep][i] = toleft[dep][l - 1] + lpos - l;
}
build(l, mid, dep + 1);
build(mid + 1, r, dep + 1);
}

//查询区间第k大的数,[L,R]是大区间,[l,r]是要查询的小区间
int query(int L, int R, int l, int r, int dep, int k)
{
if (l == r) return tree[dep][l];
int mid = (L + R) >> 1;
int cnt = toleft[dep][r] - toleft[dep][l - 1];
if (cnt >= k)
{
int newl = L + toleft[dep][l - 1] - toleft[dep][L - 1];
int newr = newl + cnt - 1;
return query(L, mid, newl, newr, dep + 1, k);
}
else
{
int newr = r + toleft[dep][R] - toleft[dep][r];
int newl = newr - (r - l - cnt);
return query(mid + 1, R, newl, newr, dep + 1, k - cnt);
}
}

struct node
{
int kind, l, r, v;
} op[150010];

int id[150010];

int main()
{
int ca = 1;
int n;
while (~scanf("%d", &n))
{
printf("Case %d:\n", ca++);
char s[30];
int cnt = 1;
int num = 0;
memset(tree, 0, sizeof(tree));
for (int i = 0; i < n; i++)
{
scanf("%s", s);
if (s[0] == 'I')
{
int v;
scanf("%d", &v);
sorted[cnt] = id[cnt] = tree[0][cnt] = v;
cnt++;
}
else if (s[0] == 'Q' && s[6] == '1')
{
scanf("%d%d%d", &op[num].l, &op[num].r, &op[num].v);
op[num].kind = 1;
num++;
}
else if (s[0] == 'Q' && s[6] == '2')
{
scanf("%d", &op[num].v);
op[num].l = 1, op[num].r = cnt - 1;
op[num].kind = 2;
num++;
}
else if (s[0] == 'Q' && s[6] == '3')
{
scanf("%d", &op[num].v);
op[num].l = 1, op[num].r = cnt - 1;
op[num].kind = 3;
num++;
}
}
cnt--;
// for(int i = 0; i < num; i++)
// printf("%d %d\n", op[i].kind, op[i].v);

sort(sorted + 1, sorted + cnt + 1);
build(1, cnt, 0);

long long s1 = 0, s2 = 0, s3 = 0;
for (int i = 0; i < num; i++)
{
if (op[i].kind == 1 || op[i].kind == 3)
{
int k = op[i].v;
int res = query(1, cnt, op[i].l, op[i].r, 0, k);
if (op[i].kind == 1)
s1 += res;
else
s3 += res;
}
else
{
int li = 1;
int ri = op[i].r - op[i].l + 1;
while (li < ri)
{
int k = li + (ri - li + 1) / 2;
int tmp = query(1, cnt, op[i].l, op[i].r, 0, k);
if (tmp <= op[i].v)
li = k;
else
ri = k - 1;
}
s2 += li;
}
}
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: