bzoj 3110 [Zjoi2013]K大数查询

3110: [Zjoi2013]K大数查询

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 13159  Solved: 4067
[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 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操作中c<=Maxlongint

 
本题恶心的地方是还有负数。。。 还有树套树的空间需要很大 
本题常见的两种做法:  
1. 权值线段树套区间线段树,时间复杂度可以做到$O(n(logn)^2)$
由于常数较大,所以在区间线段树里面的标记我们就不下放了(标记永久化)。  
每个权值线段树代表的区间都是一个值的范围,区间线段树表示这个值范围内的数在数组里面的分布情况。  
这样待会我们要查找某个下标区间内有几个值在[l,r]范围内的数,我们就可以直接去这个区间线段树上查询了。  
附树套树代码: 
 1 #include<bits/stdc++.h>
 2 using namespace std; 
 3 #define mid (l+r)/2  
 4 #define LL  long long  
 5 int const N=600000+10;  
 6 int n,m,rt[N*10],sum,lc[N*20],rc[N*20];  
 7 LL s[N*20],tg[N*20]; 
 8 int read(){
 9     int x=0,w=0; char c=0;  
10     while (!isdigit(c)) w=w||(c=='-'),c=getchar();  
11     while (isdigit(c)) x=x*10+(c^48),c=getchar();  
12     if(w) x=-x; 
13     return x;  
14 }
15 void insert(int &x,int l,int r,int ll,int rr ){
16     if(!x) x=++sum;  
17     if(ll<=l && r<=rr){
18         tg[x]++;  
19         s[x]+=(r-l+1);  
20         return;  
21     }
22     if(ll<=mid) insert(lc[x],l,mid,ll,rr);  
23     if(rr>mid)  insert(rc[x],mid+1,r,ll,rr);  
24     s[x]=s[lc[x]]+s[rc[x]]+tg[x]*(r-l+1);  
25 }  
26 void update(int x,int l,int r,int a,int b,int c){
27     insert(rt[x],1,n,a,b);  
28     if(l==r) return;  
29     if(c<=mid) update(x<<1,l,mid,a,b,c);  
30     else update(x<<1|1,mid+1,r,a,b,c);  
31 }
32 LL  ask(int x,int l,int r,int ll,int rr){
33     if(!x) return 0;  
34     if(ll<=l && r<=rr)  return s[x];  
35     LL lnum=0,rnum=0;  
36     if(ll<=mid) lnum=ask(lc[x],l,mid,ll,rr); 
37     if(rr>mid)  rnum=ask(rc[x],mid+1,r,ll,rr);  
38     return lnum+rnum+tg[x]*(min(r,rr)-max(ll,l)+1);  
39 }
40 int query(int x,int l,int r,int a,int b,int c){
41     if(l==r) return l;  
42     LL k=ask(rt[x<<1],1,n,a,b);
43     if(k>=c) return query(x<<1,l,mid,a,b,c);  
44     else return query(x<<1|1,mid+1,r,a,b,c-k);  
45 }
46 int main(){
47     //freopen("testdata.in","r",stdin); 
48     //freopen("std.out","w",stdout);  
49     scanf("%d%d",&n,&m); 
50     while (m--){
51         int t,a,b,c; 
52         t=read(); a=read(); b=read(); c=read();  
53         //scanf("%d%d%d%d",&t,&a,&b,&c);  
54         if(t==1){
55             c=n+c;  
56             //cout<<c<<endl; 
57             c=2*n-c; 
58             //cout<<c<<endl;     
59             update(1,0,2*n,a,b,c);  
60         }else {
61             printf("%d\n",2*n-query(1,0,2*n,a,b,c)-n);  
62         }
63     } 
64     return 0; 
65 }
View Code

 

 
2.整体二分 
 
 1 #include<bits/stdc++.h>
 2 using namespace std;  
 3 int const N=50000+10; 
 4 #define lc (x<<1)  
 5 #define rc (x<<1|1)  
 6 #define mid (l+r)/2   
 7 #define LL long long 
 8 struct query{
 9     int a,b,c,id,opt; 
10     LL cnt;    
11 }q[N],ta[N],tb[N];  
12 int n,m,ans[N],vis[N];
13 LL tg[N<<2],s[N<<2];    
14 void insert(int x,int l,int r,int ll,int rr,int v){
15     if(ll<=l && r<=rr){
16         tg[x]+=v;  
17         s[x]+=(r-l+1)*v; 
18         return;  
19     }
20     if(ll<=mid) insert(lc,l,mid,ll,rr,v);  
21     if(rr>mid)  insert(rc,mid+1,r,ll,rr,v);    
22     s[x]=s[lc]+s[rc]+tg[x]*(r-l+1);  
23 }
24 LL ask(int x,int l,int r,int ll,int rr){
25     if(ll<=l && r<=rr) return s[x];  
26     LL  ret=0;  
27     if(ll<=mid) ret+=ask(lc,l,mid,ll,rr);  
28     if(rr>mid)  ret+=ask(rc,mid+1,r,ll,rr);  
29     return ret+tg[x]*(min(r,rr)-max(l,ll)+1);     
30 }
31 void calc(int l,int r,int lv,int Mid){ 
32     for(int i=l;i<=r;i++) {
33         q[i].cnt=0;  
34         if(q[i].opt==1 && q[i].c<=Mid)  
35             insert(1,1,n,q[i].a,q[i].b,1); 
36         else if(q[i].opt==2) q[i].cnt=ask(1,1,n,q[i].a,q[i].b);   
37     }
38     for(int i=l;i<=r;i++) 
39         if(q[i].opt==1 && q[i].c<=Mid) 
40             insert(1,1,n,q[i].a,q[i].b,-1);  
41 }
42 void dfs(int l,int r,int lv,int rv){
43     if(l>r) return;  
44     if(lv==rv){
45         for(int i=l;i<=r;i++)  
46             if(q[i].opt==2) { 
47                 ans[q[i].id]=lv;  
48             }
49         return ; 
50     }
51     int Mid=(lv+rv)/2;  
52     calc(l,r,lv,Mid);  
53     int s1=0,s2=0;  
54     for(int i=l;i<=r;i++){
55         if(q[i].opt==1) {
56             if(q[i].c<=Mid) ta[++s1]=q[i];  
57             else tb[++s2]=q[i]; 
58         }else {
59             if(q[i].cnt>=q[i].c) ta[++s1]=q[i];  
60             else q[i].c-=q[i].cnt,tb[++s2]=q[i];   
61         }
62     }
63     int k=l;  
64     for(int i=1;i<=s1;i++)q[k++]=ta[i];  
65     for(int i=1;i<=s2;i++)q[k++]=tb[i];  
66     dfs(l,l+s1-1,lv,Mid);      
67     dfs(l+s1,r,Mid+1,rv);  
68 }    
69 int main(){
70     scanf("%d%d",&n,&m);  
71     for(int i=1;i<=m;i++){
72         scanf("%d%d%d%d",&q[i].opt,&q[i].a,&q[i].b,&q[i].c);  
73         if(q[i].opt==1){
74             q[i].c=n+q[i].c;  
75             q[i].c=2*n-q[i].c;  
76         }else vis[i]=1;  
77         q[i].id=i;  
78     }
79     dfs(1,m,0,2*n);  
80     for(int i=1;i<=m;i++) 
81         if(vis[i]) printf("%d\n",2*n-ans[i]-n);  
82     return 0; 
83 }
View Code

 

posted @ 2019-08-18 23:49  zjxxcn  阅读(133)  评论(0编辑  收藏  举报