谁知道是CDQ分治还是整体二分呢?
首先,如果只有一个查询,我们可以在区间里二分答案。
但是对于修改和操作动态搞,二分可办不了。
树套树?
不想写这么麻烦的数据结构。
那就上我们的CDQ/整体二分吧。
把操作和结果等一起二分
整体过程:当遇到的操作是询问操作时,查询线段树里的当前区间,并将当前区间所包含的数的个数as与查询的第k大相比较,如果小于k,那么把当前询问分到左边去,并统计影响k-=as,反之,将它分到右边;当遇到的操作是加入操作时,把要加入的数和mid比较,如果大于mid,那么就把当前操作统计进去,而且当前操作会对右边产生影响,所以要分到右边去,虽然对左边也有影响,但在处理询问时已经处理,就不用考虑了。
统计:线段树维护,记录每个区间当前有多少个大于mid的数,“加入”操作里的“统计进去”即是更新当前区间的数的个数。(然而我们也可以用树状数组维护)
每次操作完,都要以区间序号为关键字重新排序。
注意,对于每次使用线段树,我们不能直接强行将整颗线段树memset,而是打删除的lazy标记,注意删除lazy标记与添加lazy标记的操作先后顺序。
最后:开long long
BZOJ
COGS
Luogu
O(f(len)logn)
然而加上线段树。
线段树递归常数大没办法,窝懒得写zkw,至于树状数组,我菜的连个区间修改都不会。
拉倒啦。。。。
有写zhw的神犇麻烦告诉窝一下速度。
#include
#include
#include
#define il inline
#define ll long long
using namespace std;
const ll maxm=300010;
ll n,m;
struct node{
ll opt,l,r,k,sum,num;
}a[maxm];
ll tree[maxm],del[maxm],adx[maxm];
ll ans[maxm];
il bool comp(node x1,node x2){return x1.sum1)]+tree[(o<<1)|1];}
il void pushdown(ll o,ll l,ll r)
{
if(del[o]&&l!=r)
{
tree[(o<<1)]=tree[(o<<1)|1]=0;
del[(o<<1)]=del[(o<<1)|1]=1;
adx[(o<<1)]=adx[(o<<1)|1]=0;
del[o]=0;
}
ll mid=(l+r)>>1;
if(adx[o]!=0&&l!=r)
{
tree[(o<<1)]+=(mid-l+1)*adx[o]; tree[(o<<1)|1]+=(r-mid)*adx[o];
adx[(o<<1)]+=adx[o]; adx[(o<<1)|1]+=adx[o];
adx[o]=0;
}
}
void modify(ll o,ll l,ll r,ll ql,ll qr,ll val)
{
pushdown(o,l,r);
if(ql<=l&&r<=qr)
{
tree[o]+=(r-l+1)*val;
adx[o]+=val;
return;
}
ll mid=(l+r)>>1;
if(ql<=mid) modify((o<<1),l,mid,ql,qr,val);
if(qr>mid) modify((o<<1)|1,mid+1,r,ql,qr,val);
update(o);
}
ll ask(ll o,ll l,ll r,ll ql,ll qr)
{
pushdown(o,l,r);
if(ql<=l&&qr>=r) return tree[o];
ll mid=(l+r)>>1;
ll anx=0;
if(ql<=mid) anx+=ask((o<<1),l,mid,ql,qr);
if(qr>mid) anx+=ask((o<<1)|1,mid+1,r,ql,qr);
return anx;
}
void slove(ll l,ll r,ll ql,ll qr)
{
if(l==r)
{
for(ll i=ql;i<=qr;i++)
if(a[i].opt==2) ans[a[i].num]=l;
return;
}
ll mid=(l+r)>>1,xl=0,xr=qr-ql+1;
tree[1]=adx[1]=0,del[1]=1;
for(ll i=ql;i<=qr;i++)
{
if(a[i].opt==1)
{
if(a[i].k<=mid) a[i].sum=++xl;
else
{
modify(1,1,n,a[i].l,a[i].r,1);
a[i].sum=++xr;
}
}
else
{
ll ax=ask(1,1,n,a[i].l,a[i].r);
if(axelse a[i].sum=++xr;
}
}
sort(a+ql,a+qr+1,comp);
slove(l,mid,ql,ql+xl-1);
slove(mid+1,r,ql+xl,qr);
}
il ll read()
{
ll x=0,w=1;
char ch=0;
while(ch<'0'||ch>'9')
{
if(ch=='-') w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*w;
}
int main()
{
//freopen("zjoi13_sequence.in","r",stdin);
//freopen("zjoi13_sequence.out","w",stdout);
n=read(),m=read();
for(ll i=1;i<=m;i++)
a[i].opt=read(),a[i].l=read(),a[i].r=read(),a[i].k=read(),a[i].num=i;
slove(0,n,1,m);
for(ll i=1;i<=m;i++)
if(ans[i]) printf("%lld\n",ans[i]);
return 0;