SDUT-3930(线段树+状压)

Problem Description

一天,一只住在 501 实验室的皮卡丘决定发奋学习,成为像 LeiQ 一样的巨巨,于是他向镇上的贤者金桔请教如何才能进化成一只雷丘。

金桔告诉他需要进化石才能进化,并给了他一个地图,地图上有 n 个小镇,他需要从这些小镇中收集进化石。

接下来他会进行 q 次操作,可能是打听进化石的信息,也可能是向你询问第 l 个小镇到第 r 个小镇之间的进化石种类。

如果是打听信息,则皮卡丘会得到一个小镇的进化石变化信息,可能是引入了新的进化石,也可能是失去了全部的某种进化石。

如果是向你询问,你需要回答他第 l 个小镇到第 r 个小镇之间的进化石种类。

Input

首先输入一个整数 T (1 <= T <= 10),代表有 T 组数据。

每组数据的第一行输入一个整数 n (1 <= n <= 100000) 和一个整数 q (1 <= q <= 100000),分别代表有 n 个小镇,表皮卡丘有 q 次操作。

接下来输入 q 行,对于每次操作,先输入操作类型,然后根据操作类型读入:

  • 1: 紧接着输入 2 个整数 a (1 <= a <= n), b (1 <= b <= 60),表示第 a 个小镇引入了第 b 种进化石
  • 2: 紧接着输入 2 个整数 a (1 <= a <= n), b (1 <= b <= 60),表示第 a 个小镇失去了全部第 b 种进化石
  • 3: 紧接着输入 2 个整数 l, r (1 <= l <= r <= n),表示他想询问从第 l 个到第 r 个小镇上可收集的进化石有哪几种
Output

对于每组输入,首先输出一行 "Case T:",表示当前是第几组数据。

对于每组数据中的每次 3 操作,在一行中按编号升序输出所有可收集的进化石。如果没有进化石可收集,则输出一个 MeiK 的百分号 "%"(不包括引号)。

Example Input
1
10 10
3 1 10
1 1 50
3 1 5
1 2 20
3 1 1
3 1 2
2 1 50
2 2 20
3 1 2
3 1 10
Example Output
Case 1:
%
50
50
20 50
%
%
思路:种类的范围不超过60,所以为树上每个节点加一个longlong值表示状态即可,之后再统计种类。 (不用状压也能过)


Code:

#include <bits/stdc++.h>
#define LL long long
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
using namespace std;
const int maxn = 100005;
LL c[maxn<<2], ans;
int n, q, opt[65];
void pushUp(int rt)
{
	c[rt] = c[rt<<1]|c[rt<<1|1];
}
void update(int cz, int key, int cur, int l, int r, int rt)
{
	if(l == r)
	{
		if(key) c[rt] |= (1ll<<cz);
		else c[rt] &= ~(1ll<<cz);
		return;
	}
	int m = (l+r) >> 1;
	if(m >= cur) update(cz, key, cur, lson);
	else update(cz, key, cur, rson);
	pushUp(rt);
}
void query(int L, int R, int l, int r, int rt)
{
	if(L <= l && R >= r)
	{
		ans |= c[rt];
		return;
	}
	int m = (l+r)>>1;
	if(L <= m) query(L, R, lson);
	if(R > m) query(L, R, rson);
}
int main()
{
	int t, q1, q2, q3, count = 0;
	scanf("%d", &t);
	while(t--)
	{
		scanf("%d %d", &n, &q);
		printf("Case %d:\n", ++count);
		memset(c, 0, sizeof c);
		for(int i = 1; i <= q; ++i)
		{
			scanf("%d %d %d", &q1, &q2, &q3);
			if(q1 == 1) update(q3, 1, q2, 1, n, 1);
			if(q1 == 2) update(q3, 0, q2, 1, n, 1);
			if(q1 == 3)
			{
				ans = 0;
				query(q2, q3, 1, n, 1);
				int tot = 0;
				for(int i = 1; i <= 60; ++i)
					if((1ll<<i)&ans) opt[tot++] = i;
				if(!tot) printf("%\n");
				else
				{	
					for(int i = 0; i < tot; ++i)
					{
						if(i != 0) printf(" ");
						printf("%d", opt[i]);
					}
					printf("\n");
				}
			}
		}
	}
	return 0;
}

继续加油~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值