【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

【样例说明】

第一个操作 后位置 1 的数只有 1 , 位置 2 的数也只有 1 。 第二个操作 后位置 1

的数有 1 、 2 ,位置 2 的数也有 1 、 2 。 第三次询问 位置 1 到位置 1 第 2 大的数 是

1 。 第四次询问 位置 1 到位置 1 第 1 大的数是 2 。 第五次询问 位置 1 到位置 2 第 3

大的数是 1 。‍

N,M<=50000,N,M<=50000

a<=b<=N

1操作中abs(c)<=N

2操作中abs(c)<=Maxlongint

一直不是很理解树套树是个什么鬼。

题解告诉我此题为线段树套线段树。一维维护权值,二维维护区间。

精髓还没有领悟到,果真我还是很弱QWQ

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #include<cstring>
 6 #define ll long long
 7 using namespace std;
 8 int a,b,c;
 9 int n,m,sz;
10 int root[200005];
11 int ls[20000005],rs[20000005],sum[20000005],lazy[20000005];
12 void pushdown(int k,int l,int r){
13     if ((!lazy[k])||l==r) return;//如果没标记或者已经到了底层
14     if (!ls[k])ls[k]=++sz;
15     if (!rs[k])rs[k]=++sz;
16     int mid=(l+r)>>1;
17     lazy[ls[k]]+=lazy[k];lazy[rs[k]]+=lazy[k];
18     sum[ls[k]]+=(mid-l+1)*lazy[k];
19     sum[rs[k]]+=(r-mid)*lazy[k];
20     lazy[k]=0;
21 }
22
23 void modify(int &k,int l,int r,int a,int b){
24     if (!k)k=++sz;
25     pushdown(k,l,r);
26     if (a==l&&b==r){
27         lazy[k]++;
28         sum[k]+=(r-l+1);
29         return;
30     }
31     int mid=(l+r)>>1;
32     if (a>mid) modify(rs[k],mid+1,r,a,b);
33     else if (b<=mid) modify(ls[k],l,mid,a,b);
34     else modify(ls[k],l,mid,a,mid),modify(rs[k],mid+1,r,mid+1,b);
35     sum[k]=sum[ls[k]]+sum[rs[k]];
36 }
37
38 void insert(){
39     int l=1,r=n,k=1;
40     while (l!=r){
41         modify(root[k],1,n,a,b);
42         int mid=(l+r)>>1;
43         if (c>mid)l=mid+1,k=k<<1|1;
44         else r=mid,k=k<<1;
45     }
46     modify(root[k],1,n,a,b);
47 }
48
49 int query(int k,int l,int r,int a,int b){
50     if (!k) return 0;
51     pushdown(k,l,r);
52     if (a==l&&b==r)return sum[k];
53     int mid=(l+r)>>1;
54     if (a>mid) return query(rs[k],mid+1,r,a,b);
55     else if (b<=mid) return query(ls[k],l,mid,a,b);
56     else return query(ls[k],l,mid,a,mid)+query(rs[k],mid+1,r,mid+1,b);
57 }
58
59 int solve(){
60     int l=1,r=n,k=1;
61     while (l!=r){
62         int t=query(root[k<<1],1,n,a,b);
63         int mid=(l+r)>>1;
64         if (t>=c)r=mid,k=k<<1;
65         else l=mid+1,k=k<<1|1,c-=t;
66     }
67     return l;
68 }
69
70 int main(){
71     freopen("sj.txt","r",stdin);
72     freopen("me.txt","w",stdout);
73     scanf("%d%d",&n,&m);
74     for (int i=1;i<=m;i++){
75         int f;
76         scanf("%d%d%d%d",&f,&a,&b,&c);
77         if (f==1)c=n-c+1,insert();
78         else printf("%d\n",n-solve()+1);
79     }
80 }
时间: 2024-08-05 06:42:10

【bzoj3110】[Zjoi2013]K大数查询的相关文章

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 #inc

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

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

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大数查询 (树套树)

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大数查询 线段树套线段树

题意:给定一个数列,维护: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大数查询 树套树

[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