vijos - P1081野生动物园 (划分树 + 线段树)
2015-09-12 14:58
363 查看
P1081野生动物园
Accepted
标签:[显示标签]
cjBBteam拥有一个很大的野生动物园。这个动物园坐落在一个狭长的山谷内,这个区域从南到北被划分成N个区域,每个区域都饲养着一头狮子。这些狮子从北到南编号为1,2,3,…,N。每头狮子都有一个觅食能力值Ai,Ai越小觅食能力越强。饲养员cmdButtons决定对狮子进行M次投喂,每次投喂都选择一个区间[I,J],从中选取觅食能力值第K强的狮子进行投喂。值得注意的是,cmdButtons不愿意对某些区域进行过多的投喂,他认为这样有悖公平。因此cmdButtons的投喂区间是互不包含的。你的任务就是算出每次投喂后,食物被哪头狮子吃掉了。
样例输入1[复制]
样例输出1[复制]
各个测试点2s
对于100%的数据,有1<=N<=100000,1<=M<=50000。
周戈林
Accepted
标签:[显示标签]
描述
cjBBteam拥有一个很大的野生动物园。这个动物园坐落在一个狭长的山谷内,这个区域从南到北被划分成N个区域,每个区域都饲养着一头狮子。这些狮子从北到南编号为1,2,3,…,N。每头狮子都有一个觅食能力值Ai,Ai越小觅食能力越强。饲养员cmdButtons决定对狮子进行M次投喂,每次投喂都选择一个区间[I,J],从中选取觅食能力值第K强的狮子进行投喂。值得注意的是,cmdButtons不愿意对某些区域进行过多的投喂,他认为这样有悖公平。因此cmdButtons的投喂区间是互不包含的。你的任务就是算出每次投喂后,食物被哪头狮子吃掉了。
格式
输入格式
输入第一行有两个数N和M。此后一行有N个数,从南到北描述狮子的觅食能力值。此后M行,每行描述一次投喂。第t+2的三个数I,J,K表示在第t次投喂中,cmdButtons选择了区间[I,J]内觅食能力值第K强的狮子进行投喂。输出格式
输出有M行,每行一个整数。第i行的整数表示在第i次投喂中吃到食物的狮子的觅食能力值。
样例1
样例输入1[复制]
7 2 1 5 2 6 3 7 4 1 5 3 2 7 1
样例输出1[复制]
3 2
限制
各个测试点2s
提示
对于100%的数据,有1<=N<=100000,1<=M<=50000。
来源
周戈林#include <map> #include <set> #include <cmath> #include <ctime> #include <queue> #include <vector> #include <cctype> #include <cstdio> #include <string> #include <cstring> #include <sstream> #include <cstdlib> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define pb push_back #define mp make_pair #define fillchar(a, x) memset(a, x, sizeof(a)) #define copy(a, b) memcpy(a, b, sizeof(a)) typedef long long LL; typedef pair<int, int > PII; typedef unsigned long long uLL; template<typename T> void print(T* p, T* q, string Gap = " ") { int d = p < q ? 1 : -1; while(p != q) { cout << *p; p += d; if(p != q) cout << Gap; } cout << endl; } template<typename T> void print(const T &a, string bes = "") { int len = bes.length(); if(len >= 2)cout << bes[0] << a << bes[1] << endl; else cout << a << endl; } const int INF = 0x3f3f3f3f; const int MAXM = 1e5; const int MAXN = 1e5 + 5; LL sum[20][MAXN]; int tree[20][MAXN], sorted[MAXN]; int N, M, I, J, K; void build(int rt, int l, int r) { int mid = (l + r) >> 1, p = l, q = mid + 1, same = mid - l + 1;//得到应该平分为二的大小 for(int i = l; i <= mid ; i ++) {//小于的话先去掉 if(sorted[i] < sorted[mid]) same --; } for(int i = l; i <= r; i ++) { if(i == l) { sum[rt][i] = 0; } else { sum[rt][i] = sum[rt][i - 1]; } if(tree[rt][i] == sorted[mid]) { if(same) {//如果相同就需要特殊判断相同的数字分在左边还是右边 same --; sum[rt][i] ++; tree[rt + 1][p ++] = tree[rt][i]; } else { tree[rt + 1][q ++] = tree[rt][i]; } } else if(tree[rt][i] < sorted[mid]) { sum[rt][i] ++; tree[rt + 1][p ++] = tree[rt][i]; } else { tree[rt + 1][q ++] = tree[rt][i]; } } if(l == r) return; build(rt + 1, l, mid); build(rt + 1, mid + 1, r); } int query(int rt,int l, int r, int L, int R, int k) { int s, ss, mid = (l + r) >> 1; if(l == r) return tree[rt][l]; if(l == L) { s = 0, ss = sum[rt][R]; } else { s = sum[rt][L - 1];//得到[l, L - 1]在左边的大小 ss = sum[rt][R] - s;//得到[L, R]在左边的大小 } if(k <= ss) { return query(rt + 1, l, mid, l + s, l + s + ss - 1, k);//如果分在左边的话,取l + 左边的数 } else { return query(rt + 1, mid + 1, r, mid + 1 + L - l - s, mid + 1 + R - l - s - ss, k - ss);//如果分在右边的话取mid + 1 + 分在右边的数 } } int main() { while(cin >> N >> M) { for(int i = 1 ; i <= N ; i ++) { cin >> sorted[i]; tree[0][i] = sorted[i]; } sort(sorted + 1, sorted + N + 1); build(0, 1, N); while(M --) { cin >> I >> J >> K; print(query(0, 1, N, I, J, K)); } } return 0; }
相关文章推荐
- 云计算的三种服务模式:IaaS,PaaS和SaaS
- 高版本JDBC驱动加载的补充说明
- C++的sort函数逆序排序
- 文件的编码
- 无名指纹门禁无管理员帐号如何新增员工
- win7 64位旗舰版电脑被唤醒之后显示器依然黑屏怎么办?
- 大四实习之路
- 华为机试 寻找最大正方形
- Linux内核笔记——内存管理之块内存分配
- POJ 1741/1987 树的点分治
- Drainage Ditches---hdu1532(最大流, 模板)
- JS-prototype的掌握
- Android Studio 简介及导入 jar 包和第三方开源库方法
- python第二章
- springIOC注解
- 好玩的命令
- JSP学习笔记
- 员工打卡系统
- shell script的连接符是逗号,不是英文的句号
- openfire开发中添加日志输出