bzoj 3110 [Zjoi2013]K大数查询
3110: [Zjoi2013]K大数查询
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 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
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
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 }
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 }