BZOJ 3110 [Zjoi2013]K大数查询
题
O∧O http://www.lydsy.com/JudgeOnline/problem.php?id=3110
解
首先对输入的操作1的数字c离散化。
然后建一棵线段树,这个线段树中,li=a,ri=b这一位置存放 满足li<=c<=ri的的数字c们所对应线段树
这些内层的线段树是根据区间来构造的,比如对于c∈(x,y)的线段树,在li=a,ri=b的位置记录了区间[a,b]中有多少c∈(x,y)的c。
(思路来自某其他博客)
//http://www.lydsy.com/JudgeOnline/problem.php?id=3110 #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; typedef long long ll; const int N=100044; const int M=N*256; struct Input { int op,a,b,c; } input[55555]; int mp[N],lmp; int root[N*4],lc[M],rc[M],lazy[M],tnum; ll sum[M]; int n,m; ll count(int id,int li,int ri,int L,int R) { if(L<=li && ri<=R) return sum[id]; ll ret=(min(R,ri)-max(L,li)+1)*lazy[id],mid=(li+ri)>>1; if(mid>=L) ret+=count(lc[id],li,mid,L,R); if(mid+1<=R) ret+=count(rc[id],mid+1,ri,L,R); return ret; } int query(int L,int R,ll K) { int li=1,ri=n,mid,now=1; ll tmp; while(li!=ri) { mid=(li+ri)>>1; tmp=count(root[now*2+1],1,n,L,R); //lc: now*2 (li~mid) rc:now*2+1 (mid+1~ri) if(tmp<K) //in the left part { ri=mid; now=now*2; K-=tmp; } else { li=mid+1; now=now*2+1; } } return li; } void modify(int &id,int li,int ri,int L,int R) { int mid=(li+ri)>>1; if(!id) id=++tnum; if(L<=li && ri<=R) { sum[id]+=ri-li+1; ++lazy[id]; return ; } if(mid>=L) modify(lc[id],li,mid,L,R); if(mid+1<=R) modify(rc[id],mid+1,ri,L,R); sum[id]=sum[lc[id]]+sum[rc[id]]+lazy[id]*(ri-li+1); } void deal(int L,int R,int num) { int li=1,ri=n,mid,now=1; while(li!=ri) { modify(root[now],1,n,L,R); mid=(li+ri)>>1; if(mid<num) //choose the right child { li=mid+1; now=now*2+1; } else //choose the left child { ri=mid; now=now*2; } } modify(root[now],1,n,L,R); } void solve(int op_num) { int op,a,b,c,i; for(i=1;i<=op_num;i++) { op=input[i].op; a=input[i].a; b=input[i].b; c=input[i].c; if(op==1) //update deal(a,b,c); else //query { int ans=query(a,b,c); printf("%d\n",mp[ans]); } } } inline void read(int &ret) { int k=0; char f=1; char c=getchar(); for(;!isdigit(c);c=getchar() ) if(c=='-') f=-1; for(;isdigit(c);c=getchar() ) k=k*10+c-'0'; ret=k*f; } void init(int op_num) { int i,j; for(i=1;i<=op_num;i++) { read(input[i].op); read(input[i].a); read(input[i].b); read(input[i].c); } lmp=0; for(i=1;i<=op_num;i++) if(input[i].op==1) mp[++lmp]=input[i].c; sort(mp+1,mp+lmp+1); lmp=unique(mp+1,mp+lmp+1)-(mp+1); for(i=1;i<=op_num;i++) if(input[i].op==1) input[i].c=lower_bound(mp+1,mp+lmp+1,input[i].c)-mp; } int main() { int i,j; scanf("%d%d",&n,&m); init(m); solve(m); return 0; } /* 2 5 1 1 2 -11 1 1 2 -22 2 1 1 2 2 1 1 1 2 1 2 3 */