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 }