BZOJ3110 [ZJOI2013] K大数查询
2016-03-07 17:45
337 查看
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3110
如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
接下来M行,每行形如1 a b c或2 a b c
Orz hzwer!黄学长太神啦!
去翻题解,看到可以用树状数组套主席树,然而我不理解其中奥妙,只能打权值线段树套区间线段树
注意题意,在一个“位置”上可能会有多个数
然而求的是区间第K大,不是排名为K的数,一个位置上可能有多个数,这样一个区间内有多少个数根本不知道
结果去黄学长博客,才注意到“1操作中abs(c)<=N”,而且数据没有负数
于是就可以将插入的数 c 转换为 n - c + 1,然后就可以将区间第K大转换为查询区间排名为K的数
放学后将内层线段树改为指针版本,速度没有变快反而慢了几十到一百毫秒,指针写得丑也呵呵哒
下图是数组版代码的评测结果,代码是奇丑无比的指针版的
另外貌似结构体比数组快?
2016.3.8 update: KPM加强数据,下面的代码被叉,新的题解见这里:/article/6141539.html
View Code
Description
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
Input
第一行N,M接下来M行,每行形如1 a b c或2 a b c
Output
输出每个询问的结果Orz hzwer!黄学长太神啦!
去翻题解,看到可以用树状数组套主席树,然而我不理解其中奥妙,只能打权值线段树套区间线段树
注意题意,在一个“位置”上可能会有多个数
然而求的是区间第K大,不是排名为K的数,一个位置上可能有多个数,这样一个区间内有多少个数根本不知道
结果去黄学长博客,才注意到“1操作中abs(c)<=N”,而且数据没有负数
于是就可以将插入的数 c 转换为 n - c + 1,然后就可以将区间第K大转换为查询区间排名为K的数
放学后将内层线段树改为指针版本,速度没有变快反而慢了几十到一百毫秒,指针写得丑也呵呵哒
下图是数组版代码的评测结果,代码是奇丑无比的指针版的
另外貌似结构体比数组快?
2016.3.8 update: KPM加强数据,下面的代码被叉,新的题解见这里:/article/6141539.html
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #define rep(i,l,r) for(int i=l; i<=r; i++) #define clr(x,y) memset(x,y,sizeof(x)) using namespace std; const int maxn = 50010; inline int read(){ int ans = 0, f = 1; char c = getchar(); for(; !isdigit(c); c = getchar()) if (c == '-') f = -1; for(; isdigit(c); c = getchar()) ans = ans * 10 + c - '0'; return ans * f; } struct Node{ int s,t; Node *ls,*rs; inline void maintain(){ s = ls->s + rs->s; } }t[20000010],*pt = t,*null,*rt[maxn<<2]; int n,m,f,a,b,c; inline Node* newnode(){ pt->s = pt->t = 0; pt->ls = pt->rs = null; return pt++; } inline void init(){ null = newnode(); rep(i,1,n<<2) rt[i] = null; } inline void pushdown(Node *p,int l,int r){ if (!p->t || l == r) return; if (p->ls == null) p->ls = newnode(); if (p->rs == null) p->rs = newnode(); p->ls->t += p->t; p->rs->t += p->t; int mid = (l + r) >> 1; p->ls->s += (mid - l + 1) * p->t; p->rs->s += (r - mid) * p->t; p->t = 0; } void modify(int u,int v,Node *&p,int l,int r){ if (p == null) p = newnode(); pushdown(p,l,r); if (u == l && v == r){ p->s += (r - l + 1); p->t ++; return; } int mid = (l + r) >> 1; if (v <= mid) modify(u,v,p->ls,l,mid); else if (u > mid) modify(u,v,p->rs,mid+1,r); else{ modify(u,mid,p->ls,l,mid); modify(mid+1,v,p->rs,mid+1,r); } p->maintain(); } int query(int u,int v,Node *p,int l,int r){ if (p == null) return 0; pushdown(p,l,r); if (u == l && v == r) return p->s; int mid = (l + r) >> 1; if (v <= mid) return query(u,v,p->ls,l,mid); else if (u > mid) return query(u,v,p->rs,mid+1,r); else return query(u,mid,p->ls,l,mid) + query(mid+1,v,p->rs,mid+1,r); } void insert(){ int k = 1, l = 1, r = n; while (l < r){ int mid = (l + r) >> 1; modify(a,b,rt[k],1,n); if (c <= mid) r = mid, k <<= 1; else l = mid + 1, k = k << 1 | 1; } modify(a,b,rt[k],1,n); } int solve(){ int k = 1, l = 1, r = n; while (l < r){ int mid = (l + r) >> 1; int t = query(a,b,rt[k<<1],1,n); if (t >= c) r = mid, k <<= 1; else l = mid + 1, k = k << 1 | 1, c -= t; } return l; } int main(){ n = read(); m = read(); init(); rep(i,1,m){ f = read(); a = read(); b = read(); c = read(); if (f == 1){ c = n - c + 1; insert(); } else printf("%d\n",n - solve() + 1); } return 0; }
View Code
相关文章推荐
- Android onclick监听 接口回调机制 解析
- CNN两篇好文章
- 推荐系统-矩阵分解原理详解
- LintCode- 合并区间
- 浅谈WPF中的PreviewTextInput
- 2018-02-03-PY3下经典数据集iris的机器学习算法举例-零基础
- python Queue学习
- Android札记
- hbase的并发控制机制
- Linux中的线程局部存储
- Java虚拟机有两种类装载器
- 一致性Hash算法
- 最大公约数求法
- Mac vim iterm2配色方案
- ubuntu基本操作和web环境搭建
- [iOS]监控屏幕旋转
- 中奖率算法,方便修改中奖率
- BZOJ(本校) 3048 染色 - dp&递推找规律
- 树--天平问题
- nginx安装