线段树 - 状态压缩
链接:https://www.nowcoder.com/acm/contest/105/H
来源:牛客网
题目描述
n个桶按顺序排列,我们用1~n给桶标号。有两种操作:
1 l r c 区间[l,r]中的每个桶中都放入一个颜色为c的球 (1≤l,r ≤n,l≤r,0≤c≤60)
2 l r 查询区间[l,r]的桶中有多少种不同颜色的球 (1≤l,r ≤n,l≤r)
1 l r c 区间[l,r]中的每个桶中都放入一个颜色为c的球 (1≤l,r ≤n,l≤r,0≤c≤60)
2 l r 查询区间[l,r]的桶中有多少种不同颜色的球 (1≤l,r ≤n,l≤r)
输入描述:
有多组数据,对于每组数据:
第一行有两个整数n,m(1≤n,m≤100000)
接下来m行,代表m个操作,格式如题目所示。
输出描述:
对于每个2号操作,输出一个整数,表示查询的结果。
示例1
输入
10 10 1 1 2 0 1 3 4 1 2 1 4 1 5 6 2 2 1 6 1 7 8 1 2 3 8 1 8 10 3 2 1 10 2 3 8
输出
2 3 2 4 3
题意:直接看题目描述就可以
思路分析 : 一个线段树就可以,用二进制状态表示对应的颜色位有没有气球
代码示例:
#define ll long long const ll maxn = 1e5+5; const ll mod = 1e9+7; const double eps = 1e-9; const double pi = acos(-1.0); const ll inf = 0x3f3f3f3f; #define lson k<<1 #define rson k<<1|1 ll n, m; struct node { ll l, r; ll f; ll x; }t[maxn<<2]; void build(ll l, ll r, ll k){ t[k].l = l, t[k].r = r; t[k].f = 0, t[k].x = 0; if (l == r) return; ll m = (l+r)>>1; build(l, m, lson); build(m+1, r, rson); } void pushdown(ll k){ t[lson].x |= t[k].f; t[rson].x |= t[k].f; t[lson].f |= t[k].f; t[rson].f |= t[k].f; t[k].f = 0; } void pushup(ll k){ t[k].x = t[lson].x|t[rson].x; } void update(ll l, ll r, ll c, ll k){ if (l <= t[k].l && t[k].r <= r){ t[k].x |= (1ll<<c); t[k].f |= (1ll<<c); return; } if (t[k].f) pushdown(k); ll m = (t[k].l+t[k].r)>>1; if (l <= m) update(l, r, c, lson); if (r > m) update(l, r, c, rson); pushup(k); } ll ans; void query(ll l, ll r, ll k){ if (l <= t[k].l && t[k].r <= r){ ans |= t[k].x; return; } if (t[k].f) pushdown(k); ll m = (t[k].l + t[k].r)>>1; if (l <= m) query(l, r, lson); if (r > m) query(l, r, rson); } ll fun(){ ll x = ans; ll cnt = 0; while(x){ if (x%2) cnt++; x /= 2; } return cnt; } ll pt, l, r, c; int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); while(~scanf("%lld%lld", &n, &m)){ build(1, n, 1); for(ll i = 1; i <= m; i++){ scanf("%lld%lld%lld", &pt, &l, &r); if (pt == 1){ scanf("%lld", &c); update(l, r, c, 1); } else { ans = 0; query(l, r, 1); printf("%lld\n", fun()); } } } return 0; }
东北日出西边雨 道是无情却有情