BZOJ3110 [ZJOI2013] K大数查询(加强数据)

原来的题解:http://www.cnblogs.com/jimzeng/p/bzoj3110.html

有必要特意再写一篇题解……

OrzKPM!KPM加了两组数据结果我原来的代码就被叉了……

看到数据没有负数KPM就加了负数,然后还卡了long long(极端情况:50000次,每次在1,50000中加入一个同样的数)

需要离散化数据,加long long

然后速度就明显慢了……(9556ms -> 12292ms)

贴代码:

 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 typedef long long ll;
 9 const int maxn = 50010;
10 inline int read(){
11     int ans = 0, f = 1;
12     char c = getchar();
13     for(; !isdigit(c); c = getchar())
14     if (c == ‘-‘) f = -1;
15     for(; isdigit(c); c = getchar())
16     ans = ans * 10 + c - ‘0‘;
17     return ans * f;
18 }
19 struct Node{
20     int ls,rs; int t; ll s;
21 }t[20000010];
22 struct Function{
23     int f,a,b,c;
24 }f[maxn];
25 int n,m,N,sz = 0,cnt = 0,id[maxn],rt[maxn<<2];
26 inline void pushdown(int w,int l,int r){
27     if (!t[w].t || l == r) return;
28     if (!t[w].ls) t[w].ls = ++sz;
29     if (!t[w].rs) t[w].rs = ++sz;
30     t[t[w].ls].t += t[w].t; t[t[w].rs].t += t[w].t;
31     int mid = (l + r) >> 1;
32     t[t[w].ls].s += (mid - l + 1) * t[w].t;
33     t[t[w].rs].s += (r - mid) * t[w].t;
34     t[w].t = 0;
35 }
36 void modify(int u,int v,int &w,int l,int r){
37     if (!w) w = ++sz;
38     pushdown(w,l,r);
39     if (u == l && v == r){
40         t[w].s += (r - l + 1);
41         t[w].t++; return;
42     }
43     int mid = (l + r) >> 1;
44     if (v <= mid) modify(u,v,t[w].ls,l,mid);
45     else if (u > mid) modify(u,v,t[w].rs,mid+1,r);
46     else{
47         modify(u,mid,t[w].ls,l,mid);
48         modify(mid+1,v,t[w].rs,mid+1,r);
49     }
50     t[w].s = t[t[w].ls].s + t[t[w].rs].s;
51 }
52 ll query(int u,int v,int w,int l,int r){
53     if (!w) return 0;
54     pushdown(w,l,r);
55     if (u == l && v == r) return t[w].s;
56     int mid = (l + r) >> 1;
57     if (v <= mid) return query(u,v,t[w].ls,l,mid);
58     else if (u > mid) return query(u,v,t[w].rs,mid+1,r);
59     else return query(u,mid,t[w].ls,l,mid) + query(mid+1,v,t[w].rs,mid+1,r);
60 }
61 void insert(int a,int b,int c){
62     int k = 1, l = 1, r = N;
63     while (l < r){
64         int mid = (l + r) >> 1;
65         modify(a,b,rt[k],1,n);
66         if (c <= mid) r = mid, k <<= 1;
67         else l = mid + 1, k = k << 1 | 1;
68     }
69     modify(a,b,rt[k],1,n);
70 }
71 int solve(int a,int b,int c){
72     int k = 1, l = 1, r = N;
73     while (l < r){
74         int mid = (l + r) >> 1;
75         ll t = query(a,b,rt[k<<1],1,n);
76         if (t >= c) r = mid, k <<= 1;
77         else l = mid + 1, k = k << 1 | 1, c -= t;
78     }
79     return id[N - l + 1];
80 }
81 int main(){
82     n = read(); m = read();
83     rep(i,1,m){
84         f[i].f = read(), f[i].a = read(), f[i].b = read(), f[i].c = read();
85         if (f[i].f == 1) id[++cnt] = f[i].c;
86     }
87     sort(id+1,id+cnt+1);
88     N = unique(id+1,id+cnt+1) - id - 1;
89     rep(i,1,m) if (f[i].f == 1) f[i].c = lower_bound(id+1,id+N+1,f[i].c) - id;
90     rep(i,1,m){
91         if (f[i].f == 1){
92             f[i].c = N - f[i].c + 1; insert(f[i].a,f[i].b,f[i].c);
93         }
94         else printf("%d\n",solve(f[i].a,f[i].b,f[i].c));
95     }
96     return 0;
97 }

时间: 2024-12-23 19:21:53

BZOJ3110 [ZJOI2013] K大数查询(加强数据)的相关文章

bzoj3110: [Zjoi2013]K大数查询

喜闻乐见的简单树套树= =第一维按权值建树状数组,第二维按下标建动态开点线段树,修改相当于第二维区间加,查询在树状数组上二分,比一般的线段树还短= =可惜并不能跑过整体二分= =另外bzoj上的数据有负数= =额其他树套树方法也是可以的爱怎么套怎么套= = #include<cstdio> #define J (i+j>>1) #define I (J+1) typedef unsigned ll; const int N=1e5+5; ll n,m,q,i,j,k,l,s,t,v

bzoj3110: [Zjoi2013]K大数查询 【树套树,标记永久化】

好久没写题解了. 但是这题太神了然后做法太神了于是写一下. 这题做法很多,比如黄学长hzw的权值线段树套线段树,比如学长云的bit套主席树(其实是写法更神然后我不会用). 然后看到hzhwcmhf大神题解. http://tieba.baidu.com/p/2246783535 震惊了. 好了开说说做法.建一颗朴素的线段树,树的每个点表示每个区间,然后每个区间建两棵树,一棵是mark树,一棵是all树,两棵都是权值线段树. “mark表示该区间每个点上都会加上mark线段树里的元素 all表示该

BZOJ3110 ZJOI2013 K大数查询 线段树套线段树

题意:给定一个数列,维护:1.在a和b之间插入c  2.询问[a,b]中的第c大 题解: 权值线段树套区间线段树 外层的权值线段树中每个节点如果维护[L,R]这个区间,那么该节点所对应的线段树维护的就是[L,R]这些数在每个区间里出现了几次,也就是说如果外层线段树的某个节点维护[L,R],其所对应的内层线段树中某个节点[l,r]维护的值就是[L,R]这些数在[l,r]这个区间中出现的次数. 最后吐槽一下动态内存+指针版线段树MLE……尼玛我写指针版完全习惯了根本就不会写数组版了QAQ,自己拿数据

[BZOJ3110] [Zjoi2013] K大数查询 (树套树)

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 输出每个询问的结果 Sample Input 2 5 1 1 2 1 1 1 2 2 2 1 1 2 2 1 1 1 2 1 2 3 Sample Output 1 2 1 HINT [

【BZOJ3110】[Zjoi2013]K大数查询 树套树

[BZOJ3110][Zjoi2013]K大数查询 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 输出每个询问的结果 Sample Input 2 5 1 1 2 1 1 1 2 2 2 1 1 2 2 1 1 1 2 1 2 3

洛谷 P3332 [ZJOI2013]K大数查询 || bzoj3110

用树套树就很麻烦,用整体二分就成了裸题.... 错误: 1.尝试线段树套平衡树,码农,而且n*log^3(n)慢慢卡反正我觉得卡不过去 2.线段树pushdown写错...加法tag对于区间和的更新应该要乘上区间长度的 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 typedef long long LL; 6 struct Q 7 { 8 LL

BZOJ 3110: [Zjoi2013]K大数查询( 树状数组套主席树 )

BIT+(可持久化)权值线段树, 用到了BIT的差分技巧. 时间复杂度O(Nlog^2(N)) ----------------------------------------------------------------------------------------- #include<cstdio> #include<cctype> #include<cstring> #include<algorithm> using namespace std;

BZOJ 3110: [Zjoi2013]K大数查询 [树套树]

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6050  Solved: 2007[Submit][Status][Discuss] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a

3110: [Zjoi2013]K大数查询 树状数组套线段树

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1384  Solved: 629[Submit][Status] 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