【题目】
CC
一条长度为 n n n的数轴,每个整点初始未被标记,要求支持两种操作:
【解题思路】
考虑标记一个点 x x x会对哪些线段产生影响。我们分别找到这个点左边和右边第一个未被标记的点 l , r l,r l,r,那么左端点在 [ l + 1 , x ] [l+1,x] [l+1,x],右端点在 [ x , r − 1 ] [x,r-1] [x,r−1]的所有线段都会有贡献。
由于每个线段只会被贡献一次,不妨将每条线段按左端点插入线段树中,叶子节点维护一个堆,记下以当前位置为左端点的右端点最左的线段是什么。然后线段树上每个节点维护区间有多少个左端点,以及这些左端点对应的最小的右端点。
这样加入的时候直接加入对应堆并更新信息,标记根据线段树上维护的信息来得到答案。
复杂度 O ( ( n + Q ) log n ) O((n+Q)\log n) O((n+Q)logn)
【参考代码】
#include
using namespace std;
const int N=1e6+10,inf=0x3f3f3f3f;
int n,Q,ans,lef[N],rig[N];
priority_queue<int,vector<int>,greater<int> >q[N];
namespace IO
{
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
void write(int x){if(x>9)write(x/10);putchar(x%10^48);}
void writeln(int x){write(x);putchar('\n');}
}
using namespace IO;
struct Segment
{
#define ls (x<<1)
#define rs (x<<1|1)
int mi[N<<2];
void build(int x,int l,int r)
{
mi[x]=inf;
if(l==r) return;
int mid=(l+r)>>1;
build(ls,l,mid);build(rs,mid+1,r);
}
void insert(int x,int l,int r,int L,int R)
{
if(l==r)
{
q[l].push(R);mi[x]=min(mi[x],R);
return;
}
int mid=(l+r)>>1;
if(L<=mid) insert(ls,l,mid,L,R);
else insert(rs,mid+1,r,L,R);
mi[x]=min(mi[ls],mi[rs]);
}
void query(int x,int l,int r,int L,int R,int lim)
{
if(l==r)
{
while(!q[l].empty() && q[l].top()<=lim) q[l].pop(),++ans;
mi[x]=q[l].empty()?inf:q[l].top();
return;
}
int mid=(l+r)>>1;
if(L<=mid && mi[ls]<=lim) query(ls,l,mid,L,R,lim);
if(R>mid && mi[rs]<=lim) query(rs,mid+1,r,L,R,lim);
mi[x]=min(mi[ls],mi[rs]);
}
#undef ls
#undef rs
}T;
int findl(int x){return lef[x]==x?x:lef[x]=findl(lef[x]);}
int findr(int x){return rig[x]==x?x:rig[x]=findr(rig[x]);}
int main()
{
#ifdef Durant_Lee
freopen("CC_SEGMENTQ.in","r",stdin);
freopen("CC_SEGMENTQ.out","w",stdout);
#endif
n=read();Q=read();
for(int i=0;i<=n+1;++i) lef[i]=rig[i]=i;
T.build(1,1,n);
while(Q--)
{
int op=read(),x=read(),y;
if(!op)
{
y=read();
if(findr(x)<=y) T.insert(1,1,n,x,y);
}
else
{
int l=findl(x-1)+1,r=findr(x+1)-1;ans=0;lef[x]=l-1;rig[x]=r+1;
T.query(1,1,n,l,x,r);writeln(ans);fflush(stdout);
}
}
return 0;
}