统计颜色
题目链接: 2018年湘潭大学程序设计竞赛 - 统计颜色
题意
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)
思路一(错误的)
这道题一看就是线段树嘛,我就开始了套模板之旅,我原本是想在tree中加一个maxall来统计总共不同的数量,但是,这在PushDown和PushUp中展现出了非常大的难度,所以我就在每个tree里面开了一个have数组,来记录有没有出现过,这么如此简单粗暴的方法当然不可能过,又T又超内存了
思路二
经过同伴提醒,我突然想到了long long类型的大小就是2的63次方,这下操作就会非常简单了,无论是add还是原来的数,只需要进行操作 ‘|’ 就行了….果然过了
代码 (long long)
#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = (int)(j);i <= (int)(k);i ++)
#define per(i,j,k) for(int i = (int)(j);i >= (int)(k);i --)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define lson rt<<1
#define rson rt<<1|1
typedef long long ll;
const ll INF = (ll)0x3f3f3f3f;
const ll MAXN = (ll)1e5+2;
struct Node{
ll kin;
ll add;
}tree[MAXN*4];
void PushUp(ll rt) {
tree[rt].kin = tree[rson].kin | tree[lson].kin;
}
void PushDown(ll rt){
if (tree[rt].add){
ll t = tree[rt].add;
tree[lson].add |= t;
tree[lson].kin |= t;
tree[rson].add |= t;
tree[rson].kin |= t;
tree[rt].add = 0;
}
}
void Update(ll L,ll R,ll C,ll l,ll r,ll rt){
if (L <= l && r <= R){
tree[rt].kin |= C;
tree[rt].add |= C;
return ;
}
ll m = (l+r)>>1;
PushDown(rt);
if (L <= m) Update(L,R,C,l,m,lson);
if (R > m) Update(L,R,C,m+1,r,rson);
PushUp(rt);
}
ll Query(ll L,ll R,ll l,ll r,ll rt){
if (L <= l && r <= R){
return tree[rt].kin;
}
ll m = (l+r)>>1;
PushDown(rt);
ll res = 0;
if (L <= m) res |= Query(L,R,l,m,lson);
if (R > m) res |= Query(L,R,m+1,r,rson);
return res;
}
int main()
{
ll n,m;
while (~scanf("%lld %lld",&n,&m)){
mmm(tree,0);
ll op,L,R,va;
while (m --){
scanf("%lld %lld %lld",&op,&L,&R);
if (op == 1){
scanf("%lld",&va);
Update(L,R,(ll)1<<va,1,n,1);
}else {
ll ans = Query(L,R,1,n,1);
ll ttt = 0;
while (ans){
if (ans&1)ttt++;
ans >>= 1;
}
printf("%lld\n",ttt);
}
}
}
}
思路三
在看别人代码时,好像突然看到了一些奇怪的东西——bitset (C++ bitset 常用函数及运算符),这个东西非常好用,消耗的空间大致为size/8吧,相同情况下的bool需要的内存是它的8倍,并且bitset还有大量的内置运算,非常好用的’|’和count吧,还能用memset()来清空呢。
代码(bitset)
#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = (int)(j);i <= (int)(k);i ++)
#define per(i,j,k) for(int i = (int)(j);i >= (int)(k);i --)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define lson rt<<1
#define rson rt<<1|1
typedef long long ll;
typedef bitset<63> bi;
const int INF = (int)0x3f3f3f3f;
const int MAXN = (int)1e5+2;
struct Node{
bi kin; //像数组一样直接定义即可
bi add;
}tree[MAXN<<2];
void PushUp(int rt) {
tree[rt].kin = tree[rson].kin | tree[lson].kin; //可直接进行|运算
}
void PushDown(int rt){
if (tree[rt].add.any()){ //只要有一个数为1就返回true
bi t = tree[rt].add;
tree[lson].add |= t;
tree[lson].kin |= t;
tree[rson].add |= t;
tree[rson].kin |= t;
tree[rt].add = 0; //难以置信,可直接清零
}
}
void Update(int L,int R,ll C,int l,int r,int rt){
if (L <= l && r <= R){
tree[rt].kin |= C;
tree[rt].add |= C;
return ;
}
int m = (l+r)>>1;
PushDown(rt);
if (L <= m) Update(L,R,C,l,m,lson);
if (R > m) Update(L,R,C,m+1,r,rson);
PushUp(rt);
}
bi Query(int L,int R,int l,int r,int rt){
if (L <= l && r <= R){
return tree[rt].kin;
}
int m = (l+r)>>1;
PushDown(rt);
bi res = 0;
if (L <= m) res |= Query(L,R,l,m,lson);
if (R > m) res |= Query(L,R,m+1,r,rson);
return res;
}
int main()
{
int n,m;
while (~scanf("%d %d",&n,&m)){
mmm(tree,0); //可以用mmm直接清零
int op,L,R,va;
while (m --){
scanf("%d %d %d",&op,&L,&R);
if (op == 1){
scanf("%d",&va);
Update(L,R,(ll)1<<va,1,n,1);
}else {
bi ans = Query(L,R,1,n,1);
printf("%d\n",ans.count());//返回其中一的数量
}
}
}
}