http://www.lydsy.com/JudgeOnline/problem.php?id=3110
https://www.luogu.org/problem/show?pid=3332
带插入的区间k值啊。。。
这个啊,用主席树我不会做,这个我只会树套树
外层权值线段树,内层区间线段树
把k大改成k小很简单,取反即可哦(很方便因为abs(c)<=n)
然后介绍一下思路
外层修改和查找时的过程等同于找链,类似于二分
内层等同于线段树区间修改和区间查询
意义呢其实和前面的poj题目是差不多的
感觉我的程序有bug但是居然AC了,欢迎hack
这题还有整体二分的做法。。。博主太懒了QAQ。。。
#include<bits/stdc++.h>
using namespace std;
typedef unsigned int in;
inline in read(){
in k=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){k=k*10+ch-'0';ch=getchar();}
return k*f;
}
in root[200001],t[10000001],lt[10000001],rt[10000001],add[10000001],cnt=0;//数组开大点
in n,m,x,y,z;
inline void nxg(in l,in r,in& nod){//内层修改
if(!nod)nod=++cnt;
if(l>=x&&r<=y){add[nod]++;t[nod]+=r-l+1;return;}
in mid=(l+r)>>1;
if(x<=mid)nxg(l,mid,lt[nod]);
if(y>mid)nxg(mid+1,r,rt[nod]);
t[nod]=t[lt[nod]]+t[rt[nod]]+add[nod]*(r-l+1);
}
inline void xg(in l,in r,in nod){//外层修改
while(1){
nxg(1,n,root[nod]);
if(l==r)return;
in mid=(l+r)>>1;
if(z<=mid){r=mid;nod*=2;continue;}
l=mid+1;(nod*=2)++;
}
}
inline in ns(in l,in r,in nod){//内层查询
if(!nod)return 0;
if(l>=x&&r<=y)return t[nod];
in mid=(l+r)>>1,sum=0;
if(x<=mid)sum+=ns(l,mid,lt[nod]);
if(y>mid)sum+=ns(mid+1,r,rt[nod]);
return sum+add[nod]*(min(y,r)-max(l,x)+1);
}
inline in s(in l,in r,in nod){//外层查询
while(1){
if(l==r)return l;
in mid=(l+r)>>1,cmp=ns(1,n,root[nod*2]);
if(z<=cmp){r=mid;nod*=2;continue;}
z-=cmp;l=mid+1;(nod*=2)++;
}
}
int main()
{
n=read();m=read();
for(in i=1;i<=m;i++){
in c=read();x=read();y=read();z=read();
if(c==1)z=n-z+1,xg(1,n,1);//取个反求k小
else printf("%d\n",n-s(1,n,1)+1);//再取个反就是k大啦
}
return 0;
}