[Zjoi2013]K大数查询
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 9629 Solved: 2848
[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
题解:第一维是权值线段树,因为N的范围就这么点,这道题虽然说abs(c)<=n,但是并没有负数和0,^_^,
所以只需要1-n的权值线段树(每个点都代表一段权值)即可,第二维是区间,表示哪些位置,然后二分判断即可。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 7 #define NN 300007 8 #define MM 15000007 9 using namespace std; 10 inline int read () 11 { 12 int x=0,f=1;char ch=getchar(); 13 while(ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();} 14 while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} 15 return x*f; 16 } 17 18 int n,m,tot; 19 int root[NN],ls[MM],rs[MM]; 20 long long cnt[MM],ly[MM]; 21 22 void update(int &u,int l,int r,int x,int y)//u开地址传输 23 { 24 if (!u) u=++tot;//假如没有这个点。 25 if (l>=x&&r<=y) 26 { 27 cnt[u]+=r-l+1;++ly[u];//lazy TAG 28 return; 29 } 30 int mid=(l+r)>>1; 31 if (y<=mid) update(ls[u],l,mid,x,y); 32 else if (x>mid) update(rs[u],mid+1,r,x,y); 33 else update(ls[u],l,mid,x,mid),update(rs[u],mid+1,r,mid+1,y); 34 cnt[u]+=y-x+1; 35 } 36 void add(int x,int y,int val) 37 { 38 int l=1,r=n,u=1,mid; 39 while (true) 40 { 41 update(root[u],1,n,x,y); 42 if (l==r) break; 43 mid=(l+r)>>1,u<<=1; 44 if (val<=mid) r=mid; 45 else l=mid+1,u|=1; 46 } 47 } 48 long long count(int u,int l,int r,int x,int y) 49 { 50 if (l==x&&r==y) return cnt[u];//记录个数,因为保证了答案个数。 51 int mid=(l+r)>>1;long long ans=0; 52 if (y<=mid) ans=count(ls[u],l,mid,x,y); 53 else if (x>mid) ans=count(rs[u],mid+1,r,x,y); 54 else ans=count(ls[u],l,mid,x,mid)+count(rs[u],mid+1,r,mid+1,y); 55 ans+=(y-x+1)*ly[u]; 56 return ans; 57 } 58 int query(int x,int y,long long val) 59 { 60 int l=1,r=n,mid,u=1;long long tmp;//因为放进去的数最大是n。 61 while(l<r) 62 { 63 mid=(l+r)>>1; 64 tmp=count(root[u<<1|1],1,n,x,y); 65 if (tmp>=val) l=mid+1,u=u<<1|1;//维护权值线段树 66 else r=mid,u=u<<1,val-=tmp; 67 } 68 return l; 69 } 70 int main() 71 { 72 n=read(),m=read(); 73 while (m--) 74 { 75 int flag=read(),a=read(),b=read(),c=read(); 76 if (flag==1)add(a,b,c); 77 else printf("%d ",query(a,b,c)); 78 } 79 }