题目:我是超链接
题解:
首先这题与最传统线段树区别在于:统计区间不同数字个数。不过你可以看到修改的颜色是连续的,且不超过30.这就非常好办了,直接状态压缩要修改的颜色。然后线段树上把左右孩子按位或起来便是。最后区间答案中转成二进制里“1”的个数便是不同数字个数。
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int sum[400005],delta[400005];
void updata(int now){sum[now]=(sum[now<<1]|sum[now<<1|1]);}
void build(int now,int l,int r)
{
if (l==r) {sum[now]=1;return;}
int mid=(l+r)>>1;
if (l<=mid) build(now<<1,l,mid);
if (r>mid) build(now<<1|1,mid+1,r);
updata(now);
}
void pushdown(int now)
{
if (delta[now])
{
delta[now<<1]=delta[now]; delta[now<<1|1]=delta[now];
sum[now<<1]=delta[now]; sum[now<<1|1]=delta[now];
delta[now]=0;
}
}
void change(int now,int l,int r,int lrange,int rrange,int k)
{
if (lrange<=l && rrange>=r){sum[now]=k; delta[now]=k;return;}
int mid=(l+r)>>1;pushdown(now);
if (lrange<=mid) change(now<<1,l,mid,lrange,rrange,k);
if (rrange>mid) change(now<<1|1,mid+1,r,lrange,rrange,k);
updata(now);
}
int qurry(int now,int l,int r,int lrange,int rrange)
{
if (lrange<=l && rrange>=r) return sum[now];
pushdown(now);//这个pushdown如果加在外面就会越界GG
int mid=(l+r)>>1,ans=0;
if (lrange<=mid) ans|=qurry(now<<1,l,mid,lrange,rrange);
if (rrange>mid) ans|=qurry(now<<1|1,mid+1,r,lrange,rrange);
updata(now);
return ans;
}
int main()
{
int l,t,o,i,a,b,c;
scanf("%d%d%d",&l,&t,&o);
build(1,1,l);
for (i=1;i<=o;i++)
{
char s[5];
scanf("%s%d%d",s,&a,&b);
if (a>b) swap(a,b);
if (s[0]=='C')
{
scanf("%d",&c);
change(1,1,l,a,b,1<<c-1);
}
else
{
int ans=0;
int v=qurry(1,1,l,a,b);
while (v){ans+=v&1; v>>=1;}
printf("%d\n",ans);
}
}
}
本文介绍了一种利用线段树进行状态压缩的方法,解决区间内不同数字个数的统计问题。通过具体实例展示了如何使用状态压缩技巧更新线段树节点,并实现区间查询功能。
986

被折叠的 条评论
为什么被折叠?



