题意

传送门

给定MMM个城市,每年会选出一个城市举办比赛,现给出前NNN年城市举办比赛的情况。在接下来的年份中,每年的比赛会在举办比赛次数最小的城市举办,如果有很多城市举办次数均为最小值,则在编号最小的城市举办比赛。现给出 QQQ个询问,每次询问第 KKK 年在哪个城市举办比赛。

分析

由于个人习惯,把题目中的nnn和mmm意义互换。

我们可以把问题抽象成有nnn个宽度相等高度不同的矩形,给出初始高度,每次选取最矮的矩形中编号最小的,并把它的高度+1,然后不断重复这个操作,要求回答第KKK次选取的矩形的编号。

我们看到要选取编号最小的,那么毫不犹豫先排序。(遇事不决先排序)

于是我们可以把原问题变成如下图一样:

我们发现有几个高度相同的矩形会组成一段“平台”。于是想想怎么求这种“平台”。

如果我单独地把一段“平台拿出来”,由于高度相同,那么它们被选择的顺序一定是按编号大小排序并形成循环的。那么假如我要在这个平台的基础上求第kkk次选择,那么我们实际上求的是这段平台中编号第k%lenk \% lenk%len小的(其中lenlenlen是平台的长度,并且如果k%len=0k\%len=0k%len=0,那么就是编号最大的)。

那么这个求平台中第kkk小的操作就可以使用权值线段树平衡树维护。


然而很不幸,我们的问题中显然不只一个平台,所以我们考虑从低到高进行“填坑操作”。偷一张官方题解的图。

为了处理方便,我们把询问离线,按照kkk的大小(即先后顺序)排序。

比如在这张图中,前三个矩形构成了两个平台,那么我们发现高度更高的{2,5}\{2,5\}{2,5}并不会对333产生影响,必须得等到333到达{2,5}\{2,5\}{2,5}的高度后才会被影响。那么我们就可以放心地先把333填至{2,5}\{2,5\}{2,5}的高度,然后把333加入到平台中形成{2,3,5}\{2,3,5\}{2,3,5}这样的一个平台。显然经过填坑操作后,所有的平台都是原序列的前缀。在填坑过程中,有一些询问是可以被回答的,那么就通过平台的性质进行回答。同时我们也要把新加入到平台的元素插入到权值线段树中,以便下一次查询。


实现细节

在处理平台和询问的时候可以分别记录一个指针,表示当前处理到哪一个矩形或询问。同时再维护一个nownownow表示当前已经进行了几次选择(初始值为给定的已操作次数)。然后对于矩形,每次向后找到一个平台,在此过程中把平台中的矩形编号插入到权值线段树中。接着向后枚举询问,如果当前的nownownow加上下一个平台被填满所需的操作次数大于询问,那么说明这个询问可以在这次填坑中被回答,那么在权值线段树中查询得到答案。最后nownownow累加上填坑所需操作次数即可。

复杂度

我们的两个指针都是线性扫描的,所以处理询问部分是O((n+q)logn)O((n+q)logn)O((n+q)logn)的,由于前面需要一遍排序也需要O(nlogn)O(nlogn)O(nlogn)的时间,所以总复杂度O((n+q)logn)O((n+q)logn)O((n+q)logn)。

代码

#include <bits/stdc++.h>
#define ll long long
#define MAX 500005
#define lc(x) (x<<1)
#define rc(x) (x<<1|1)
#define mid ((l+r)>>1)
using namespace std;namespace sgt{int s[MAX*4];void push_up(int p){s[p] = s[lc(p)]+s[rc(p)];}void update(int p, int l, int r, int u, int k){if(l == r){s[p] += k;return;}if(mid >= u) update(lc(p), l, mid, u, k);else update(rc(p), mid+1, r, u, k);push_up(p);}int query(int p, int l, int r, int k){if(l == r) return l;if(s[lc(p)] >= k){return query(lc(p), l, mid, k);}else return query(rc(p), mid+1, r, k-s[lc(p)]);}
}
//以上权值线段树模板struct ask{      //询问离线ll k, id;friend bool operator <(ask a, ask b){return a.k < b.k;}
}q[MAX];struct city{        //矩形ll h, id;friend bool operator <(city a, city b){if(a.h == b.h) return a.id < b.id;return a.h < b.h;}
}a[MAX];int n, m;
ll Q, now, p, p1, p2, ans[MAX];int main()
{cin >> m >> n >> Q;for(int i = 1; i <= n; ++i){a[i].id = i;}ll x;for(int i = 1; i <= m; ++i){scanf("%lld", &x);a[x].h++;}sort(a+1, a+n+1);for(int i = 1; i <= Q; ++i){scanf("%lld", &q[i].k);q[i].id = i;}sort(q+1, q+Q+1);//初始化:排序、离线p1 = p2 = 1;now = m;while(p1 <= n){p = p1;while(a[p].h == a[p1].h){        //向后找平台,并插入到权值线段树中sgt::update(1, 1, n, a[p].id, 1);p++;}while(now+(a[p].h-a[p1].h)*(p-1) >= q[p2].k){     //处理在这次填坑范围内的询问ll t = (q[p2].k-now)%(p-1);if(!t) t = p-1;ans[q[p2].id] = sgt::query(1, 1, n, t);p2++;}now += (a[p].h-a[p1].h)*(p-1);     //累加操作次数p1 = p;            //下一次平台的开始}for(int i = 1; i <= Q; ++i){//可能还有一些询问没有处理,但此时所有矩形都已形成一个平台,直接回答,甚至不需要权值线段树if(!ans[q[i].id]){ll t = (q[i].k-now)%n;if(!t) t = n;ans[q[i].id] = t;}}for(int i = 1; i <= Q; ++i){printf("%lld\n", ans[i]);}return 0;
}

【题解】CF1181D Irrigation相关推荐

  1. TYUT-A专题题解(一)

    TYUT-A专题题解(一) 01A Ad Hoc UVA353 LA5247 Pesky Palindromes[回文] - 海岛Blog - CSDN博客 UVA947 Master Mind He ...

  2. [JS][dfs]题解 | #迷宫问题#

    题解 | #迷宫问题# 题目链接 迷宫问题 题目描述 定义一个二维数组 N*M ,如 5 × 5 数组下所示: int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 1, 1 ...

  3. [JS][dp]题解 | #打家劫舍(一)#

    题解 | #打家劫舍(一)# 题目链接 打家劫舍(一) 题目描述 描述 你是一个经验丰富的小偷,准备偷沿街的一排房间,每个房间都存有一定的现金,为了防止被发现,你不能偷相邻的两家,即,如果偷了第一家, ...

  4. [JS]题解 | #魔法数字#

    题解 | #魔法数字# 题目链接 魔法数字 题目描述 牛妹给牛牛写了一个数字n,然后又给自己写了一个数字m,她希望牛牛能执行最少的操作将他的数字转化成自己的. 操作共有三种,如下: 在当前数字的基础上 ...

  5. [JS]题解 | #岛屿数量#

    题解 | #岛屿数量# 题目链接 岛屿数量 题目描述 时间限制:1秒 空间限制:256M 描述 给一个01矩阵,1代表是陆地,0代表海洋, 如果两个1相邻,那么这两个1属于同一个岛.我们只考虑上下左右 ...

  6. [JS] 题解:提取不重复的整数

    题解:提取不重复的整数 https://www.nowcoder.com/practice/253986e66d114d378ae8de2e6c4577c1 时间限制:1秒 空间限制:32M 描述 输 ...

  7. 洛谷-题解 P2672 【推销员】

    独门思路!链表加优先队列! 这题一望,贪心是跑不掉了,但是我贪心并不好,所以想到了一个复杂一些但思路更保稳的做法 思路: 1 因为是离线操作,所以我们可以倒着求,先求x=n的情况,因为那样直接就知道了 ...

  8. [洛谷1383]高级打字机 题解

    题解 这道题一看就珂以用主席树啊 这是一道神奇的题目,那么我们先敲一个主席树,然后维护一个数组len,表示下一次应该在len + 1插入, 之后对于T操作,在上一个版本的len + 1上直接执行插入 ...

  9. luogu P1549 棋盘问题(2) 题解

    luogu P1549 棋盘问题(2) 题解 题目描述 在\(N * N\)的棋盘上\((1≤N≤10)\),填入\(1,2,-,N^2\)共\(N^2\)个数,使得任意两个相邻的数之和为素数. 例如 ...

最新文章

  1. 记录值上调10_「阴阳师」10月16日维护更新公告,海国迷踪,迷影重重
  2. 【Win7下Android native code的编译和调试】
  3. 1.网页学习-开始学习第一步:
  4. SQL Server 2008 正式版安装指南(附序列号)
  5. LINUx打包命令汇总
  6. 人才缺口40万,摆地摊也没有它挣钱,这个神仙职业今年太火了!
  7. C++——求值顺序例子
  8. 统计学习方法c++实现之二 k近邻法
  9. geohash redis mysql_Redis geohash 地理位置存储
  10. 1.0-并发编程-进程和线程简介
  11. Linux学习第一节课学习心得
  12. Linux UDP协议栈中的片段分析 - udp_recvmsg
  13. c语言 strcpy作用,c语言中的strcpy什么意思,简单点解释
  14. 硬件在环(一):HIL起始
  15. 百度云 不限速 | 2019 最好用下载工具
  16. 深大计算机图形学大作业之虚拟场景建模
  17. CUDA安装和检测【全】(nvcc命令找不到的解决办法)
  18. 脑洞 博弈 E. Competitive Seagulls 2017 ACM Arabella Collegiate Programming Contest
  19. 页面静态化--Nginx
  20. ISP Tuning—高通Chromatix6

热门文章

  1. Fish vs. Zsh vs. Bash以及为什么要改用Fish
  2. Seaborn数据可视化
  3. python实现一个简单的计时器
  4. NLP语义技术演进:从DP依存句法到SDP依存语义再到AMR抽象语义分析概述与开源实现...
  5. Android短信收发
  6. 每日一算法:矩阵中最大正方形面积
  7. PHP:关于PHP商城秒杀防止超卖问题
  8. bugku-细心(想办法变成admin)
  9. oracle ebs web agent,《ORACLE EBS Web ADI深入浅出》.pdf
  10. C语言验证码--自学第三天