博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
洛谷 P1533 可怜的狗狗
阅读量:4486 次
发布时间:2019-06-08

本文共 3579 字,大约阅读时间需要 11 分钟。

洛谷 P1533 可怜的狗狗

Description

  • 小卡家有N只狗,由于品种、年龄不同,每一只狗都有一个不同的漂亮值。漂亮值与漂亮的程度成反比(漂亮值越低越漂亮),吃饭时,狗狗们会按顺序站成一排等着主人给食物。

    可是嘉嘉真的很懒,他才不肯喂这么多狗呢,这多浪费时间啊,于是他每次就只给第i只到第j只狗中第k漂亮的狗狗喂食(好狠心的人啊)。而且为了保证某一只狗狗不会被喂太多次,他喂的每个区间(i,j)不互相包含。

Input

  • 第一行输入两个数n,m,你可以假设n<300001 并且 m<50001;m表示他喂了m次。

    第二行n个整数,表示第i只狗的漂亮值为ai。

    接下来m行,每行3个整数i,j,k表示这次喂食喂第i到第j只狗中第k漂亮的狗的漂亮值。

Output

  • M行,每行一个整数,表示每一次喂的那只狗漂亮值为多少。

Sample Input

7 21 5 2 6 3 7 41 5 32 7 1

Sample Output

3

2

题解:

  • 平衡树。
  • 首先一说这题解法很多,莫队、主席树、划分树、线段树、平衡树。
  • 这题用平衡树还是比较巧妙的。观察到题目中有这么一个性质:每个区间(i,j)不互相包含。这就说明,原本下列的3种情况:(/为占位符)

//第一种

………..

///…………

//第二种

………..

///……

//第三种

………..

// ………

  • 只会变成下列两种

//第一种

………..

///…………

//第二种

………..

/ ………

  • 那么先离线把区间保存下来,按左端点从小到大排序。如果与上一个区间有重叠部分:就删掉上一个区间中与当前区间不重叠的部分,再加上当前新的部分。如果与上一个区间没有重叠部分,就删掉上一个区间,添加当前区间。这样操作就可以得到当前区间。
  • 有了这样的性质,每个位置的元素至多被删除/添加一次,复杂度就是O(nlogn),完全可以接受。
#include 
#include
#include
#define N 300005#define M 50005#define inf 0x7fffffffusing namespace std;struct T {int l, r, val, dat, cnt, size;} t[N];struct B {int l, r, k, id;} b[M];int n, m, root, tot;int a[N], ans[M];int read(){ int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();} while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();} return x *= f;}bool cmp(B x, B y){ if(x.l == y.l) return x.r < y.r; return x.l < y.l;}void up(int p) {t[p].size = t[t[p].l].size + t[t[p].r].size + t[p].cnt;}int New(int val){ t[++tot].val = val, t[tot].dat = rand(); t[tot].size = t[tot].cnt = 1; return tot;}void zig(int &y){ int x = t[y].l; t[y].l = t[x].r, t[x].r = y, y = x; up(t[y].r), up(y);}void zag(int &x){ int y = t[x].r; t[x].r = t[y].l, t[y].l = x, x = y; up(t[x].l), up(x);}void insert(int &p, int val){ if(!p) {p = New(val); return;} if(val == t[p].val) {t[p].cnt++, up(p); return;} if(val < t[p].val) { insert(t[p].l, val); if(t[t[p].l].dat > t[p].dat) zig(p); } else { insert(t[p].r, val); if(t[t[p].r].dat > t[p].dat) zag(p); } up(p);}void erase(int &p, int val){ if(!p) return; if(val == t[p].val) { if(t[p].cnt > 1) {t[p].cnt--, up(p); return;} if(t[p].l || t[p].r) { if(!t[p].r || t[t[p].l].dat > t[t[p].r].dat) zig(p), erase(t[p].r, val); else zag(p), erase(t[p].l, val); up(p); } else p = 0; return; } val < t[p].val ? erase(t[p].l, val) : erase(t[p].r, val); up(p);}int valOfRank(int p, int rank){ if(!p) return inf; if(t[t[p].l].size >= rank) return valOfRank(t[p].l, rank); if(t[t[p].l].size + t[p].cnt >= rank) return t[p].val; return valOfRank(t[p].r, rank - t[t[p].l].size - t[p].cnt);}int main(){ New(inf), New(-inf), root = 1, t[1].l = 2, up(1); cin >> n >> m; for(int i = 1; i <= n; i++) a[i] = read(); for(int i = 1; i <= m; i++) { b[i].l = read(), b[i].r = read(); b[i].k = read(), b[i].id = i; } sort(b + 1, b + 1 + m, cmp); for(int i = 1; i <= m; i++) { if(b[i - 1].r >= b[i].l) { for(int j = b[i - 1].l; j < b[i].l; j++) erase(root, a[j]); for(int j = b[i - 1].r + 1; j <= b[i].r; j++) insert(root, a[j]); } else { for(int j = b[i - 1].l; j <= b[i - 1].r; j++) erase(root, a[j]); for(int j = b[i].l; j <= b[i].r; j++) insert(root, a[j]); } ans[b[i].id] = valOfRank(root, b[i].k + 1); } for(int i = 1; i <= m; i++) printf("%d\n", ans[i]); return 0;}

转载于:https://www.cnblogs.com/BigYellowDog/p/11329568.html

你可能感兴趣的文章
Android 演示 Android ListView 和 github XListView(3-3)
查看>>
JQuery攻略(四)事件
查看>>
开发框架-异常处理机制
查看>>
用yum快速搭建LAMP平台
查看>>
关于百度编辑器使用遇到的一些问题
查看>>
洛谷 P1649 [USACO07OCT]【障碍路线Obstacle Course(最少转弯问题)】
查看>>
Splash闪屏页-三种动画效果
查看>>
C#读取wav文件
查看>>
mongodb循环插入测试数据
查看>>
设计模式-10-装饰器
查看>>
测试技术提升建议
查看>>
中兴手机刷机
查看>>
【转】使用 Auto Layout 的典型痛点和技巧
查看>>
c++动态链接库的创建和使用
查看>>
django-树形结构
查看>>
LeetCode & Q38-Count and Say-Easy
查看>>
bnuoj 51275 并查集按深度合并建树
查看>>
观察者(Observer)模式
查看>>
Vulkan Tutorial 13 Render passes
查看>>
使SWT/JFace支持跨平台
查看>>