HDU 3727 Jewel(划分树 + 二分)

来源:互联网 发布:python 3.6.0下载安装 编辑:程序博客网 时间:2024/06/05 02:59

题目链接: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--;}elsetree[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;elses3 += 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;elseri = k - 1;}s2 += li;}}cout << s1 << endl;cout << s2 << endl;cout << s3 << endl;}return 0;}


0 0
原创粉丝点击