题目
一眼似乎不可做。。。结果眼瞎看错题了,切了切了
做法
化简题意:(n)个集合,(m)次操作(集合区间添数,集合区间查询(K)大值)
外层值域线段树+内存区间线段树,自己去随便(yy)一下也能切掉吧
还是讲一下具体做法:添的数(long long)以内,值域线段树空间会被卡,去重
关于添数,找到(c)在值域内的位置,结果的线段树内层((a,b)+1),其实这个树套树维护的就是在((l,r))这个值域集合区间出现的数
有点卡常:值域非递归做一下,(int)和(long long)要准确区分位置,吸波氧可过
My complete code
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
typedef int LL;
const LL maxn=20000000;
inline LL Read(){
LL x(0),f(1);char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*f;
}
struct Qy{
LL op,a,b;
long long c;
}q[maxn];
LL n,m,nod,cnt;
LL son[maxn][2],root[maxn];
long long tmp[maxn],sum[maxn],lazy[maxn];
inline void Update(LL now){
sum[now]=sum[son[now][0]]+sum[son[now][1]];
}
inline void Pushdown(LL now,LL l,LL r){
LL val(lazy[now]);
if(val){
LL mid(l+r>>1);
lazy[now]=0;
if(!son[now][0]) son[now][0]=++nod;
if(!son[now][1]) son[now][1]=++nod;
LL lc(son[now][0]),rc(son[now][1]);
lazy[lc]+=val,lazy[rc]+=val,
sum[lc]+=(mid-l+1)*val,sum[rc]+=(r-mid)*val;
}
}
void Add(LL &now,LL l,LL r,LL lt,LL rt){
if(!now) now=++nod;
if(lt<=l&&rt>=r){
sum[now]+=(r-l+1),
++lazy[now];
return;
}
Pushdown(now,l,r);
LL mid(l+r>>1);
if(lt<=mid) Add(son[now][0],l,mid,lt,rt);
if(rt>mid) Add(son[now][1],mid+1,r,lt,rt);
Update(now);
}
long long Query(LL now,LL l,LL r,LL lt,LL rt){
if(!now) return 0;
if(lt<=l&&rt>=r) return sum[now];
Pushdown(now,l,r);
LL mid(l+r>>1);long long ret(0);
if(lt<=mid) ret+=Query(son[now][0],l,mid,lt,rt);
if(rt>mid) ret+=Query(son[now][1],mid+1,r,lt,rt);
return ret;
}
void SAdd(LL x,LL l,LL r,LL c,LL a,LL b){
while(l!=r){
Add(root[x],1,n,a,b);
LL mid(l+r>>1);
if(c<=mid)
x=(x<<1),r=mid;
else
x=(x<<1|1),l=mid+1;
}
Add(root[x],1,n,a,b);
}
LL SQuery(LL x,LL l,LL r,LL a,LL b,long long K){
while(l!=r){
LL mid(l+r>>1);long long ret=Query(root[x<<1|1],1,n,a,b);
if(K<=ret)
x=(x<<1|1),l=mid+1;
else
x=(x<<1),r=mid,K-=ret;
}return tmp[l];
}
int main(){
n=Read(),m=Read();
for(LL i=1;i<=m;++i){
q[i]=(Qy){Read(),Read(),Read(),0};
scanf("%lld",&q[i].c);
if(q[i].op==1) tmp[++cnt]=q[i].c;
}
sort(tmp+1,tmp+1+cnt),cnt=unique(tmp+1,tmp+1+cnt)-tmp-1;
for(LL i=1;i<=m;++i){
if(q[i].op==1){
LL val(lower_bound(tmp+1,tmp+1+cnt,q[i].c)-tmp);
SAdd(1,1,cnt,val,q[i].a,q[i].b);
}else
printf("%lld
",SQuery(1,1,cnt,q[i].a,q[i].b,q[i].c));
}return 0;
}