1 条题解
-
0
题意分析
- 初始状态:长度为的木板,所有段颜色为。
- 操作类型:
- 染色操作():将区间染成颜色,需处理的情况(即交换)。
- 查询操作():统计区间内不同颜色的数量。
- 关键约束:颜色总数,可用位压缩优化状态存储。
解题思路
- 线段树设计:
- 每个节点存储区间颜色的位掩码(位二进制数,第位为表示存在颜色)。
- 合并子节点时,通过按位或操作合并颜色集合。
- 懒标记:记录区间染色操作的待更新颜色,优化区间修改性能。
- 查询处理:统计区间颜色掩码中的位数(使用__builtin_popcount)。
实现步骤
- 初始化:建树时所有节点颜色掩码为(初始颜色)。
- 区间染色(操作):
- 若,交换。
- 更新线段树区间的掩码为,并下传懒标记。
- 区间查询(操作):
- 查询区间的掩码,计算其中的个数。
- 边界处理:操作前检查是否越界()。
复杂度分析
- 时间:每次操作,总复杂度。
- 空间:线段树开节点,。
代码实现
#include<cstdio> #include<cstring> #define lc ((rt)<<1) #define rc ((rt)<<1|1) #define maxn 100010 int ans[50]; struct node{ int l,r,color; }tree[maxn*4]; void build(int rt,int l,int r){//创建线段树 tree[rt].l=l; tree[rt].r=r; if(rt!=1) tree[rt].color=0; if(l==r) return; int mid=(l+r)>>1; build(lc,l,mid); build(rc,mid+1,r); } void lift_up(int rt){//颜色统一 if(tree[lc].color==tree[rc].color) tree[rt].color=tree[lc].color; } void push_down(int rt){//颜色下传 if(tree[rt].color){ tree[lc].color=tree[rc].color=tree[rt].color; tree[rt].color=0; } } void modify(int rt,int l,int r,int c){//修改 if (tree[rt].l==l&&tree[rt].r==r){ tree[rt].color=c; return; } push_down(rt); int mid=(tree[rt].l+tree[rt].r)>>1; if(r<=mid) modify(lc,l,r,c); else if(l>mid) modify(rc,l,r,c); else {modify(lc,l,mid,c);modify(rc,mid+1,r,c);} lift_up(rt); } void query(int rt,int l,int r){//查询 if(tree[rt].color){ ans[tree[rt].color]=true; return; } int mid=(tree[rt].l+tree[rt].r)>>1;; if(r<=mid) query(lc,l,r); else if(l>mid) query(rc,l,r); else {query(lc,l,mid);query(rc,mid+1,r);} } int main(){ int n,t,o; scanf("%d%d%d",&n,&t,&o); tree[1].color=1; build(1,1,n); for(int i=0;i<o;i++){ char ch; scanf("\n%c",&ch); int l,r; if(ch=='C'){ int c; scanf("%d%d%d",&l,&r,&c); modify(1,l,r,c); } else{ memset(ans,0,sizeof(ans)); scanf("%d%d",&l,&r); query(1,l,r); int tot=0; for(int k=1;k<=t;k++) if(ans[k]) tot++; printf("%d\n",tot); } } return 0; }
- 1
信息
- ID
- 1777
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者