Description
有
N
个位置,
如果是
Input
第一行
接下来
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
的数只有
N,M<=50000,N,M<=50000
a<=b<=N
1
操作中
2
操作中
Source
思路
树套数,权值线段树套位置线段树。
如图:
这个图表示
1
号位置有一个数
首先对纵坐标建立一棵线段树(权值线段树);
再在权值线段树的每一个节点上对横坐标建立一棵线段树(位置线段树);
插入操作(
1 a b c
)就是找到权值线段树上包含
c
这个点的区间,并将这些区间的线段树上
查询操作(
代码
(超大常数和超级扩行)
#include <cstdio>
const int maxn=50000;
const int maxs=20000000;
int n;
struct pos_segment_tree//位置线段树
{
int ls[maxs],rs[maxs],cnt;
unsigned val[maxs],lazy[maxs];
inline int newnode()//为了节省空间,每访问一个节点再新建一个节点
{
++cnt;
ls[cnt]=rs[cnt]=val[cnt]=lazy[cnt]=0;
return cnt;
}
inline int pushdown(int now,int left,int right)
{
if((!lazy[now])||(left==right))
{
return 0;
}
if(!ls[now])
{
ls[now]=newnode();
}
if(!rs[now])
{
rs[now]=newnode();
}
int mid=(left+right)>>1;
val[ls[now]]+=lazy[now]*(mid-left+1);
val[rs[now]]+=lazy[now]*(right-mid);
lazy[ls[now]]+=lazy[now];
lazy[rs[now]]+=lazy[now];
lazy[now]=0;
return 0;
}
inline unsigned updata(int now)
{
return val[now]=val[ls[now]]+val[rs[now]];
}
int add(int &now,int left,int right,int askl,int askr)
{
if(!now)
{
now=newnode();
}
pushdown(now,left,right);
if((askl<=left)&&(right<=askr))
{
++lazy[now];
val[now]+=right-left+1;
return 0;
}
int mid=(left+right)>>1;
if(askl<=mid)
{
add(ls[now],left,mid,askl,askr);
}
if(mid<askr)
{
add(rs[now],mid+1,right,askl,askr);
}
updata(now);
return 0;
}
unsigned query(int now,int left,int right,int askl,int askr)
{
if(!now)
{
return 0;
}
pushdown(now,left,right);
if((askl<=left)&&(right<=askr))
{
return val[now];
}
int mid=(left+right)>>1;
unsigned int res=0;
if(askl<=mid)
{
res+=query(ls[now],left,mid,askl,askr);
}
if(mid<askr)
{
res+=query(rs[now],mid+1,right,askl,askr);
}
return res;
}
};
struct val_segment_tree//权值线段树
{
int root[maxn<<4];
pos_segment_tree pst;
int add(int now,int left,int right,int askl,int askr,int cv)
{
pst.add(root[now],1,n,askl,askr);
if(left==right)
{
return 0;
}
int mid=(left+right)>>1;
if(cv<=mid)
{
add(now<<1,left,mid,askl,askr,cv);
}
else
{
add(now<<1|1,mid+1,right,askl,askr,cv);
}
return 0;
}
int query(int now,int left,int right,int pl,int pr,unsigned int k)
{
if(left==right)
{
return left;
}
int mid=(left+right)>>1;
unsigned int eq=pst.query(root[now<<1],1,n,pl,pr);
if(eq>=k)
{
return query(now<<1,left,mid,pl,pr,k);
}
else
{
return query(now<<1|1,mid+1,right,pl,pr,k-eq);
}
}
};
val_segment_tree vst;
int m,opt,a,b,c;
int main()
{
scanf("%d%d",&n,&m);
while(m--)
{
scanf("%d%d%d%d",&opt,&a,&b,&c);
if(opt==1)
{
vst.add(1,0,n<<1,a,b,n-c);
}
else
{
printf("%d\n",n-vst.query(1,0,n<<1,a,b,c));
}
}
return 0;
}