给出
q
≤
1
e
5
q\leq1e5
q≤1e5次操作,每次向集合
S
S
S插入一个线段或者查询对于当前线段,
S
S
S中有多少个线段完全覆盖它。保证端点最大值不超过
1
e
5
1e5
1e5,并且被查询的线段的长度最多为
2
2
2。
线段树或者树状数组有多少个线段的右端点小于当前线段的右端点,有多少个线段的左端点大于当前线段的左端点,用总数减掉这些线段的个数。只有左右端点都被包含的线段被多减一次,当前仅当线段长度为
3
3
3的时候中间一个点会出现这样的情形,单独维护。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=1e5+7;
struct SegTree {
int sum[4*N];
void clear() {
memset(sum,0,sizeof(sum));
}
void pushup(int rt) {
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void modify(int rt,int l,int r,int x) {
if(l==r) {
sum[rt]++;
return;
}
int mid=(l+r)>>1;
if(x<=mid) modify(rt<<1,l,mid,x);
else modify(rt<<1|1,mid+1,r,x);
pushup(rt);
}
int query(int rt,int l,int r,int L,int R) {
if(R<l||L>r) return 0;
if(L<=l&&r<=R) return sum[rt];
int mid=(l+r)>>1;
return query(rt<<1,l,mid,L,R)+query(rt<<1|1,mid+1,r,L,R);
}
}seg[2];
int cnt[N];
int main() {
int n,q;
while(scanf("%d%d",&n,&q)!=EOF) {
seg[0].clear();
seg[1].clear();
memset(cnt,0,sizeof(cnt));
int sum=0;
for(int i=1;i<=q;i++) {
int opt,l,r;
scanf("%d%d%d",&opt,&l,&r);
if(opt==1) {
sum++;
seg[0].modify(1,1,n,l);
seg[1].modify(1,1,n,r);
if(l==r) cnt[l]++;
}
else if(opt==2) {
printf("%d\n",sum-seg[0].query(1,1,n,l+1,n)-seg[1].query(1,1,n,1,r-1)+((r-l==2)?cnt[l+1]:0));
}
}
}
return 0;
}