您的位置:首页 > 其它

BZOJ3110 [ZJOI2013] K大数查询

2016-03-07 17:45 337 查看
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3110

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: