ZJOI 2013 K大数查询

题目链接bzoj点我:-) 洛谷点我:-)
题目描述
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。

输入格式
第一行N,M接下来M行,每行形如1 a b c或2 a b c

输出格式
输出每个询问的结果

数据说明
N,M<=50000,N,M<=50000
a<=b<=N
1操作中abs(c)<=N
2操作中c<=Maxlongint

思路
本题有多法可解,比如权值线段树套区间线段树,线段树套splay,线段树套主席树,树状数组套线段树,整体二分,CDQ分治等
介绍最简单的权值线段树套区间线段树:
外层即以权值为线段树区间,内层以原区间为线段树区间,树套树。
1操作为外层线段树单点修改,内层线段树区间修改
2操作为外层线段树区间修改,内层线段树区间修改

比较卡空间,需把内层线段树动态开点。并且注意离散化和long long

感想
第一次写树套树,怎么这么卡我空间。。。洛谷不让过,硬是讲我MLE,bzoj较为善良让我过了,
但是。。居然有17000+ms。。莫非我天生自带大常数?!!

代码

 1 //miaomiao 2017.2.11
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<map>
 5 
 6 using namespace std;
 7 
 8 #define LL long long
 9 #define mid ((L+R)>>1)
10 #define For(i, a, b) for(int i = (a); i <= (int)(b); i++)
11 #define N (50000+1)
12 #define M (12000000+1)
13 
14 struct node{
15     int op, a, b;
16     LL c;
17 }qus[N];
18 
19 int lc[M], rc[M], root[N<<4], xn, num[N], val[N], ql, qr, cnt, mn;
20 LL sum[M], add[M];
21 map<LL, int> ms;
22 
23 void modify(int &o, int L, int R){
24     if(!o) o = ++cnt;
25     if(ql <= L && R <= qr){add[o]++; sum[o]+=(R-L+1); return;}
26 
27     if(ql <= mid) modify(lc[o], L, mid); if(qr > mid) modify(rc[o], mid+1, R);
28     sum[o] = sum[lc[o]]+sum[rc[o]]+add[o]*(R-L+1);
29 }
30 
31 LL query(int &o, int L, int R, LL Add){
32     if(!o) o = ++cnt;
33     if(ql <= L && qr >= R) return sum[o]+Add*(R-L+1);
34     LL ret = 0;
35     if(ql <= mid) ret += query(lc[o], L, mid, Add+add[o]);
36     if(qr > mid) ret += query(rc[o], mid+1, R, Add+add[o]);
37     return ret;
38 }
39 
40 int main(){
41     int n, m, now, L, R;
42     LL c, t;
43     scanf("%d%d", &n, &m);
44     For(i, 1, m){
45         scanf("%d%d%d%lld", &qus[i].op, &qus[i].a, &qus[i].b, &qus[i].c);
46         if(qus[i].op == 1) num[++xn] = qus[i].c;
47     }
48     sort(num+1, num+xn+1);
49     For(i, 1, xn)
50         if(num[i] != num[i-1] || i==1) ms[num[i]] = ++mn, val[mn] = num[i];
51 
52     For(i, 1, m){
53         ql = qus[i].a; qr = qus[i].b; c = qus[i].c;
54         now = 1; L = 1; R = n;
55         if(qus[i].op == 1){
56             c = ms[c];
57             while(true){
58                 modify(root[now], 1, n);
59                 if(L == R) break;
60                 if(c <= mid) now = now<<1, R = mid;
61                 else now = now<<1|1, L = mid+1;
62             }
63         }else{
64             while(L < R){
65                 t = query(root[now<<1|1], 1, n, 0);
66                 if(t >= c) L = mid+1, now = now<<1|1;    
67                 else R = mid, now = now<<1, c -= t;
68             }
69             printf("%d\n", val[L]);
70         }
71     }
72 
73     return 0;
74 }

 

 
posted @ 2017-02-11 23:15  Miao_miao  阅读(234)  评论(0编辑  收藏  举报