[2018HNCPC] H 千万别用树套树 线段树

本文介绍了一种利用线段树或树状数组解决线段覆盖问题的方法,通过计算线段的左、右端点与其他线段的关系,确定完全覆盖的线段数量。适用于端点最大值不超过1e5的场景,特别关注线段长度为2的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给出 q ≤ 1 e 5 q\leq1e5 q1e5次操作,每次向集合 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值