bzoj 3110: [Zjoi2013]K大数查询 树状数组套线段树

时间:2023-03-08 16:23:33
bzoj 3110: [Zjoi2013]K大数查询 树状数组套线段树

3110: [Zjoi2013]K大数查询

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 1384  Solved: 629
[Submit][Status]

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操作中abs(c)<=Maxlongint

  这道题本来想用线段树套平衡树做,但是即便加了永久lazy标记,还是TLE了,后来改为树状数组套线段树,注意树状数组二分可优化为O(logn)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define MAXT 8100000
#define MAXN 51009
#define lch (now<<1)
#define rch (now<<1^1)
#define INF 0x3f3f3f3f
#define L(x) SBT[x].L
#define R(x) SBT[x].R
#define S(x) SBT[x].S
#define val(x) SBT[x].val
#define tot(x) SBT[x].tot
#define sum(x) SBT[x].sum
typedef long long qword;
int n,m;
inline int nextInt()
{
register int x=;
register char ch;
while (ch=getchar(),ch<''||ch > '');
do
x=x*+ch-'';
while (ch=getchar(),ch<='' && ch>='');
return x;
}
int topt;
struct SBT_T
{
int L,R,S,val,tot,sum;
}SBT[MAXT];
inline void update(int now)
{
if (!now)return ;
S(now)=S(L(now))+S(R(now))+;
sum(now)=sum(L(now))+sum(R(now))+tot(now);
}
inline void l_rotate(int &now)
{
register int t=R(now);
R(now)=L(t);update(now);
L(t)=now;update(t);
now=t;
}
inline void r_rotate(int &now)
{
register int t=L(now);
L(now)=R(t);update(now);
R(t)=now;update(t);
now=t;
}
inline void maintain(int &now)
{
if (S(L(L(now)))>S(R(now)))
{
r_rotate(now);
//maintain(L(now));
maintain(R(now));
maintain(now);
}else if (S(R(R(now)))>S(L(now)))
{
l_rotate(now);
//maintain(R(now));
maintain(L(now));
maintain(now);
}else if (S(R(L(now)))>S(R(now)))
{
l_rotate(L(now));
r_rotate(now);
maintain(R(now));
maintain(L(now));
maintain(now);
}else if (S(L(R(now)))>S(L(now)))
{
r_rotate(R(now));
l_rotate(now);
maintain(R(now));
maintain(L(now));
maintain(now);
}
}
void Insert(int &now,int v,int t)
{
if (!now)
{
// if (topt>MAXT-10)throw 1;
now=++topt;
L(now)=R(now)=;
val(now)=v;
tot(now)=sum(now)=t;
return ;
}
if (v==val(now))
tot(now)+=t;
else if (v<val(now))
Insert(L(now),v,t);
else if (val(now)<v)
Insert(R(now),v,t);
update(now);
maintain(now);
}
/*
int Get_tot(int &now,int v)
{
if (!now)return 0;
if (val(now)==v)
return sum(L(now));
else if (v<val(now))
return Get_tot(L(now),v);
else if (val(now)<v)
return Get_tot(R(now),v)+sum(L(now))+tot(now);
return 0;
}*/
int Get_tot(int now,int v)
{
int ret=;
while (now && val(now)!=v)
{
if (v<val(now))
now=L(now);
else if (val(now)<v)
ret+=sum(L(now))+tot(now),now=R(now);
}
if (now && val(now)==v)ret+=sum(L(now));
return ret;
}
void Scan(int now)
{
if (!now)return ;
Scan(L(now));
printf("%d(%d) ",val(now),tot(now));
Scan(R(now));
}
struct sgt_node
{
int l,r;
int rt;
int lazy;
}sgt[MAXN*];
void Build_sgt(int now,int l,int r)
{
sgt[now].l=l;
sgt[now].r=r;
if (l==r)return ;
Build_sgt(lch,l,(l+r)>>);
Build_sgt(rch,((l+r)>>)+,r);
}
void Add_val(int now,int l,int r,int v)
{
Insert(sgt[now].rt,v,r-l+);
if (sgt[now].l==l && sgt[now].r==r)
{
Insert(sgt[now].lazy,v,);
return ;
}
int mid=(sgt[now].l+sgt[now].r)>>;
if (r<=mid)
{
Add_val(lch,l,r,v);
}else if (mid<l)
{
Add_val(rch,l,r,v);
}else
{
Add_val(lch,l,mid,v);
Add_val(rch,mid+,r,v);
}
}
int Qry_tot(int now,int l,int r,int v)
{
int ret=;
if (sgt[now].l==l && sgt[now].r==r)
{
return Get_tot(sgt[now].rt,v);
}
ret=Get_tot(sgt[now].lazy,v)*(r-l+);
int mid=(sgt[now].l+sgt[now].r)>>;
if (r<=mid)
ret+=Qry_tot(lch,l,r,v);
else if (mid<l)
ret+=Qry_tot(rch,l,r,v);
else
ret+=Qry_tot(lch,l,mid,v)+Qry_tot(rch,mid+,r,v);
return ret;
}
int Get_size(int now,int l,int r)
{
if (sgt[now].l==l && sgt[now].r==r)
{
return sum(sgt[now].rt);
}
int mid=(sgt[now].l+sgt[now].r)>>;
if (r<=mid)
return Get_size(lch,l,r) + sum(sgt[now].lazy)*(r-l+);
else if (mid<l)
return Get_size(rch,l,r) + sum(sgt[now].lazy)*(r-l+);
else
return Get_size(lch,l,mid)+Get_size(rch,mid+,r) + sum(sgt[now].lazy)*(r-l+);
}
int Qry_kth(int ll,int rr,int rk)
{
int l,r,mid;
l=-n;
r=n+;
rk=Get_size(,ll,rr)-rk;
int t=;
if (rk<)return ;
while (l+<r)
{
mid=(l+r)/;
t=Qry_tot(,ll,rr,mid);
if (t<=rk)
l=mid;
else
r=mid;
}
return l;
} int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
int i,j,k,x,y,z;
int rt=;
scanf("%d%d",&n,&m);
int opt;
Build_sgt(,,n);
for (i=;i<m;i++)//
{
opt=nextInt();
x=nextInt();
y=nextInt();
z=nextInt();
//scanf("%d%d%d%d",&opt,&x,&y,&z);
if (opt==)
{
Add_val(,x,y,z);
}else
{
printf("%d\n",Qry_kth(x,y,z));
}
}
}

线段树+SBT

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 101000
#define MAXT 28000000
#define lowbit(x) (x&(-x))
inline int nextInt()
{
register int x=;
register char ch;
while (ch=(char)getchar(),ch<''||ch > '');
do
x=x*+ch-'';
while (ch=(char)getchar(),ch<='' && ch>='');
return x;
} int n,m;
struct sgt_node
{
int lch,rch;
int t,lazy;
}sgt[MAXT];
int topt=;
void Add_sgt(int &now,int l,int r,int x,int y)
{
if (!now)
{
now=++topt;
sgt[now].t=sgt[now].lazy=;
}
if (l==x && r==y)
{
sgt[now].t+=r-l+;
sgt[now].lazy++;
return ;
}
int mid=(l+r)>>;
if (sgt[now].lazy)
{
if (!sgt[now].lch)
sgt[now].lch=++topt;
if (!sgt[now].rch)
sgt[now].rch=++topt;
sgt[sgt[now].lch].lazy+=sgt[now].lazy;
sgt[sgt[now].rch].lazy+=sgt[now].lazy;
sgt[sgt[now].lch].t+=sgt[now].lazy*(mid-l+);
sgt[sgt[now].rch].t+=sgt[now].lazy*(r-mid);
sgt[now].lazy=;
}
if (y<=mid)
{
Add_sgt(sgt[now].lch,l,mid,x,y);
}else if (mid<x)
{
Add_sgt(sgt[now].rch,mid+,r,x,y);
}else
{
Add_sgt(sgt[now].lch,l,mid,x,mid);
Add_sgt(sgt[now].rch,mid+,r,mid+,y);
}
sgt[now].t=sgt[sgt[now].lch].t+sgt[sgt[now].rch].t;
}
int Qry_sgt(int &now,int l,int r,int x,int y)
{
if (!now || sgt[now].t==)return ;
if (l==x && r==y)
return sgt[now].t;
int mid=(l+r)>>;
if (sgt[now].lazy)
{
if (!sgt[now].lch)
sgt[now].lch=++topt;
if (!sgt[now].rch)
sgt[now].rch=++topt;
sgt[sgt[now].lch].lazy+=sgt[now].lazy;
sgt[sgt[now].rch].lazy+=sgt[now].lazy;
sgt[sgt[now].lch].t+=sgt[now].lazy*(mid-l+);
sgt[sgt[now].rch].t+=sgt[now].lazy*(r-mid);
sgt[now].lazy=;
}
if (y<=mid)
{
return Qry_sgt(sgt[now].lch,l,mid,x,y);
}else if (mid<x)
{
return Qry_sgt(sgt[now].rch,mid+,r,x,y);
}else
{
return Qry_sgt(sgt[now].lch,l,mid,x,mid)
+Qry_sgt(sgt[now].rch,mid+,r,mid+,y);
}
}
int tarr2[MAXN],tarr3[MAXN];
void Add_tarr2(int l,int r)
{
r++;
int a=r;
while (r<MAXN)
{
tarr2[r]--;
tarr3[r]-=a;
r+=lowbit(r);
}
a=l;
while (l<MAXN)
{
tarr2[l]++;
tarr3[l]+=a;
l+=lowbit(l);
}
}
//segma((n-i+1)*a[i])
//=(n+1)*segma(a[i]) - segma(i*a[i])
int Qry_tarr2(int l,int r)
{
int ret=;
int v1,v2;
int now;
v1=;
l--;
now=r;
v1=v2=;
while (now)
{
v1+=tarr2[now];
v2+=tarr3[now];
now-=lowbit(now);
}
ret+=v1*(r+)-v2;
now=l;
v1=v2=;
while (now)
{
v1+=tarr2[now];
v2+=tarr3[now];
now-=lowbit(now);
}
ret-=v1*(l+)-v2;
return ret;
}
int tarr[MAXN];
void Add_tarr(int pos,int l,int r)
{
pos+=n+;
Add_tarr2(l,r);
while (pos<MAXN)
{
Add_sgt(tarr[pos],,n+,l,r);
pos+=lowbit(pos);
}
}
/*
int Qry_tarr(int rk,int ll,int rr)
{
int now=0,t;
int i;
int l,r,mid;
rk=Qry_tarr2(ll,rr)-rk+1;
l=-n-1;r=n+1;
while (l+1<r)
{
t=0;
mid=(l+r)>>1;
now=mid+n+1;
while (now)
{
t+=Qry_sgt(tarr[now],0,n+1,ll,rr);
now-=lowbit(now);
}
if (t<rk)
l=mid;
else
r=mid;
}
return r==-n ? 1 : r;
}*/
int Qry_tarr(int rk,int ll,int rr)
{
int now=,t;
int i;
int l,r,mid;
rk=Qry_tarr2(ll,rr)-rk+;
for (i=;i>=;i--)
{
if (now+(<<i)<MAXN && (t=Qry_sgt(tarr[now+(<<i)],,n+,ll,rr))<rk)
{
rk-=t;
now+=(<<i);
}
}
now=now+-(n+);
return now;
}
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
scanf("%d%d",&n,&m);
int i;
int opt,x,y,z;
for (i=;i<m;i++)
{
opt=nextInt();
x=nextInt();
y=nextInt();
z=nextInt();
//scanf("%d%d%d%d",&opt,&x,&y,&z);
if (opt==)
{
Add_tarr(z,x,y);
}else
{
printf("%d\n",Qry_tarr(z,x,y));
}
}
}

树状数组+线段树