K大数查询
时间限制: 2 Sec 内存限制: 512 MB
题目描述
有n 个位置和m 个操作。操作有两种,每次操作如果是1 a b c 的形式,表 示往第a 个位置到第b 个位置每个位置加入一个数c。如果操作形如2 a b c 的形 式,表示询问从第a 个位置到第b 个位置,第c 大的数是多少。
输入
在输入文件sequence.in 中,第一行两个数n,m。
意义如题目描述。 接下来m 行每行形如1 a b c 或者2 a b c 如题目描述。
输出
在输出文件sequence.out 中,对于每个询问回答k 大数是多少。
样例输入
2 5
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3
样例输出
1
2
1
提示
第一个操作后位置1 的数只有1,位置2 的数也只有1。第二个操作后位置1 的数有1、2,位置2 的数也有1、2。第三次询问位置1 到位置1 第2 大的数是 1。第四次询问位置1 到位置1 第1 大的数是2。第五次询问位置1 到位置2 第3 大的数是1。
30%的数据n=m=1000
100%的数据n,m≤50000,并且后7 个点的数据n,m 的范围从32000 到50000
来源
zjoi2013
题解
带区间修改的要求区间第K大,使用树状数组套主席树解决。
在权值线段树上存2个值,一个s1表示每个区间被加了多少次,另一个s2表示每次修改操作左区间的总和。则size=s1*(x+1)-s2。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#define N 50010
#define ll long long
using namespace std;
int n,m,t1,t2,cnt,wbs[20],cyc[20],rt[N];
struct node{int lc,rc,s1,s2;}t[N*50];
class seg_tree
{
public:
void modify(int &x,int pre,int l,int r,int des,int val,int num)
{
x=pre?pre:++cnt;
t[x]=t[pre];t[x].s1+=val;t[x].s2+=num;
if(l==r)return;
int mid=l+r>>1;
if(des<=mid)modify(t[x].lc,t[pre].lc,l,mid,des,val,num);
else modify(t[x].rc,t[pre].rc,mid+1,r,des,val,num);
}
int qry(int x,int pre,int l,int r,int k,int L,int R)
{
if(l==r)return l;
int cnt1=0,cnt2=0,mid=l+r>>1;
for(int i=1;i<=t1;i++)cnt1+=R*t[t[wbs[i]].rc].s1-t[t[wbs[i]].rc].s2;
for(int i=1;i<=t2;i++)cnt2+=L*t[t[cyc[i]].rc].s1-t[t[cyc[i]].rc].s2;
if(cnt1-cnt2>=k)
{
for(int i=1;i<=t1;i++)wbs[i]=t[wbs[i]].rc;
for(int i=1;i<=t2;i++)cyc[i]=t[cyc[i]].rc;
return qry(t[x].rc,t[pre].rc,mid+1,r,k,L,R);
}
for(int i=1;i<=t1;i++)wbs[i]=t[wbs[i]].lc;
for(int i=1;i<=t2;i++)cyc[i]=t[cyc[i]].lc;
return qry(t[x].lc,t[pre].lc,l,mid,k-cnt1+cnt2,L,R);
}
}T2;
class bit
{
public:
void modify(int x,int des,int val,int num)
{
for(;x<=n;x+=x&-x)T2.modify(rt[x],rt[x],1,n,des,val,num);
}
int qry(int l,int r,int k)
{
int x;t1=0;t2=0;
x=r;for(;x;x-=x&-x)wbs[++t1]=rt[x];
x=l;for(;x;x-=x&-x)cyc[++t2]=rt[x];
return T2.qry(rt[r],rt[l],1,n,k,l+1,r+1);
}
}T1;
int main()
{
int type,a,b,c;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d%d",&type,&a,&b,&c);
if(type==1)T1.modify(a,c,1,a),T1.modify(b,c,-1,-b-1);
else printf("%d\n",T1.qry(a-1,b,c));
}
return 0;
}