您的位置:首页 > 其它

【bzoj3110】【ZJOI2013】【K大数查询】【权值线段树套位置线段树】

2016-06-15 16:19 387 查看

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直接在权值线段树插入即可.

          操作2可以在权值线段树上二分.

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 500010
using namespace std;
int root[N<<2],ls[N*40],rs[N*40],sz,n,m,a,b,c,kind;
unsigned int sum[N*40],p[N*40];
int read(){
int x(0),f(1);
char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
void paint(int &k,int l,int r,int v){
if (!k) k=++sz;
sum[k]+=(unsigned int)(r-l+1)*v;
p[k]+=(unsigned int)v;
}
void pushdown(int k,int l,int r){
int mid=(l+r)>>1;
paint(ls[k],l,mid,p[k]);
paint(rs[k],mid+1,r,p[k]);
p[k]=0;
}
void add(int &k,int l,int r,int ll,int rr){
if (!k) k=++sz;
if (l==ll&&r==rr){sum[k]+=rr-ll+1;p[k]++;return;}
if (p[k]) pushdown(k,l,r);
int mid=(l+r)>>1;
if (rr<=mid) add(ls[k],l,mid,ll,rr);
else if (mid<ll) add(rs[k],mid+1,r,ll,rr);
else{
add(ls[k],l,mid,ll,mid);
add(rs[k],mid+1,r,mid+1,rr);
}
sum[k]=sum[ls[k]]+sum[rs[k]];
}
void insert(){
int l=1,r=n,k=1;
while (l!=r){
int mid=(l+r)>>1;
add(root[k],1,n,a,b);
if (c<=mid){k<<=1;r=mid;}
else{k=k<<1|1;l=mid+1;}
}
add(root[k],1,n,a,b);
}
unsigned int query(int k,int l,int r,int ll,int rr){
int mid=(l+r)>>1;if (!k) return 0;
if (l==ll&&r==rr){return sum[k];}
if (p[k]) pushdown(k,l,r);
if (rr<=mid) return query(ls[k],l,mid,ll,rr);
else if (mid<ll) return query(rs[k],mid+1,r,ll,rr);
else return query(ls[k],l,mid,ll,mid)+query(rs[k],mid+1,r,mid+1,rr);
}
int work(){
int l=1,r=n,k=1;
while (l!=r){
int mid=(l+r)>>1;
unsigned int temp=query(root[k<<1],1,n,a,b);
if (temp>=c){r=mid;k<<=1;}
else{k=k<<1|1;c-=temp;l=mid+1;}
}
return l;
}
int main(){
n=read();m=read();
for (int i=1;i<=m;i++){
kind=read();a=read();b=read();c=read();
if (kind==1){c=n-c+1;insert();}
if (kind==2){printf("%d\n",n-work()+1);}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: