【luogu U137441】生日(线段树)

生日

题目链接:luogu U137441

题目大意

给你一个序列一开始都是 1,然后会有把一个区间的数都改成同一个数,或者询问一个区间有多少个数。

思路

发现数的个数很少,完全可以用二进制状压出每一个数在一个区间中是否出现。

然后就可以直接拿线段树来维护。

然后就好啦,每次询问找到结果就枚举每一位判断是否有,然后记录一下个数就好了。
(你也可以直接用 bitset)

(或者你用带修莫队也行,不过没必要,数个数很少)

代码

#include<cstdio>

using namespace std;

int n, m, k, l, r, x, ans;
char c;

struct XDtree {//线段树
	int a[400001], lzy[400001];
	
	void up(int now) {
		a[now] = a[now << 1] | a[now << 1 | 1];
	}
	
	void down(int now, int l, int r) {
		if (!lzy[now]) return ;
		int mid = (l + r) >> 1;
		a[now << 1] = a[now << 1 | 1] = a[now];
		lzy[now << 1] = lzy[now << 1 | 1] = lzy[now];
		lzy[now] = 0;
	}
	
	void change(int now, int l, int r, int L, int R, int val) {
		if (L <= l && r <= R) {
			a[now] = (1 << (val - 1));
			lzy[now] = 1;
			return ;
		}
		
		down(now, l, r);
		int mid = (l + r) >> 1;
		if (L <= mid) change(now << 1, l, mid, L, R, val);
		if (mid < R) change(now << 1 | 1, mid + 1, r, L, R, val);
		up(now);
	}
	
	int query(int now, int l, int r, int L, int R) {
		if (L <= l && r <= R) {
			return a[now];
		}
		
		down(now, l, r);
		int mid = (l + r) >> 1, re = 0;
		if (L <= mid) re |= query(now << 1, l, mid, L, R);
		if (mid < R) re |= query(now << 1 | 1, mid + 1, r, L, R);
		return re;
	}
}T;

int main() {
	scanf("%d %d %d", &n, &m, &k);
	
	T.a[1] = 1; T.lzy[1] = 1;//一开始都是 1,直接打懒标记
	while (m--) {
		c = getchar();
		while (c != 'C' && c != 'P') c = getchar();
		if (c == 'C') {
			scanf("%d %d %d", &l, &r, &x);
			T.change(1, 1, n, l, r, x);
		}
		else {
			scanf("%d %d", &l, &r);
			ans = 0;
			int x = T.query(1, 1, n, l, r);
			for (int i = 0; i < k; i++)
				if ((x >> i) & 1) ans++;
			printf("%d\n", ans);
		}
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值