SDUT-3930(线段树+状压)

来源:互联网 发布:eddie griffin 知乎 编辑:程序博客网 时间:2024/06/08 02:52

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

110 103 1 101 1 503 1 51 2 203 1 13 1 22 1 502 2 203 1 23 1 10

Example Output

Case 1:%505020 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|1using 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;}

继续加油~

原创粉丝点击