BZOJ3110 [ZJOI2013] K大数查询

题目链接: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加强数据,下面的代码被叉,新的题解见这里:http://www.cnblogs.com/jimzeng/p/bzoj3110_2.html

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstring>
 5 #define rep(i,l,r) for(int i=l; i<=r; i++)
 6 #define clr(x,y) memset(x,y,sizeof(x))
 7 using namespace std;
 8 const int maxn = 50010;
 9 inline int read(){
10     int ans = 0, f = 1;
11     char c = getchar();
12     for(; !isdigit(c); c = getchar())
13     if (c == '-') f = -1;
14     for(; isdigit(c); c = getchar())
15     ans = ans * 10 + c - '0';
16     return ans * f;
17 }
18 struct Node{
19     int s,t; Node *ls,*rs;
20     inline void maintain(){
21         s = ls->s + rs->s;
22     }
23 }t[20000010],*pt = t,*null,*rt[maxn<<2];
24 int n,m,f,a,b,c;
25 inline Node* newnode(){
26     pt->s = pt->t = 0; pt->ls = pt->rs = null;
27     return pt++;
28 }
29 inline void init(){
30     null = newnode();
31     rep(i,1,n<<2) rt[i] = null;
32 }
33 inline void pushdown(Node *p,int l,int r){
34     if (!p->t || l == r) return;
35     if (p->ls == null) p->ls = newnode();
36     if (p->rs == null) p->rs = newnode();
37     p->ls->t += p->t; p->rs->t += p->t;
38     int mid = (l + r) >> 1;
39     p->ls->s += (mid - l + 1) * p->t;
40     p->rs->s += (r - mid) * p->t;
41     p->t = 0;
42 }
43 void modify(int u,int v,Node *&p,int l,int r){
44     if (p == null) p = newnode();
45     pushdown(p,l,r);
46     if (u == l && v == r){
47         p->s += (r - l + 1);
48         p->t ++; return;
49     }
50     int mid = (l + r) >> 1;
51     if (v <= mid) modify(u,v,p->ls,l,mid);
52     else if (u > mid) modify(u,v,p->rs,mid+1,r);
53     else{
54         modify(u,mid,p->ls,l,mid);
55         modify(mid+1,v,p->rs,mid+1,r);
56     }
57     p->maintain();
58 }
59 int query(int u,int v,Node *p,int l,int r){
60     if (p == null) return 0;
61     pushdown(p,l,r);
62     if (u == l && v == r) return p->s;
63     int mid = (l + r) >> 1;
64     if (v <= mid) return query(u,v,p->ls,l,mid);
65     else if (u > mid) return query(u,v,p->rs,mid+1,r);
66     else return query(u,mid,p->ls,l,mid) + query(mid+1,v,p->rs,mid+1,r);
67 }
68 void insert(){
69     int k = 1, l = 1, r = n;
70     while (l < r){
71         int mid = (l + r) >> 1;
72         modify(a,b,rt[k],1,n);
73         if (c <= mid) r = mid, k <<= 1;
74         else l = mid + 1, k = k << 1 | 1;
75     }
76     modify(a,b,rt[k],1,n);
77 }
78 int solve(){
79     int k = 1, l = 1, r = n;
80     while (l < r){
81         int mid = (l + r) >> 1;
82         int t = query(a,b,rt[k<<1],1,n);
83         if (t >= c) r = mid, k <<= 1;
84         else l = mid + 1, k = k << 1 | 1, c -= t;
85     }
86     return l;
87 }
88 int main(){
89     n = read(); m = read(); init();
90     rep(i,1,m){
91         f = read(); a = read(); b = read(); c = read();
92         if (f == 1){
93             c = n - c + 1; insert();
94         }
95         else printf("%d\n",n - solve() + 1);
96     }
97     return 0;
98 }
View Code

 

posted on 2016-03-07 17:45  ACMICPC  阅读(945)  评论(0编辑  收藏  举报

导航