题目链接
https://vjudge.z180.cn/problem/POJ-2777
题目大意:
给你一个长度为N的
[
1
,
N
]
[1,N]
[1,N]区间,一开始区间的颜色初始化为1,给你一个T表示颜色在[1,T]范围类可选,然后你有M次操作,操作有如下两种情况
1.C A B C 表示把区间
[
A
,
B
]
[A,B]
[A,B]染成颜色C
2.P A B表示查询区间
[
A
,
B
]
[A,B]
[A,B]有多少种不同颜色,并输出
分析:这道题一看区间修改加区间查询,线段树跑不掉,首先对于一个区间我们不能单纯通过它左儿子不同颜色个数+右儿子不同颜色个数来维护这个区间的不同颜色个数,你想一想如果左儿子也有红色,右儿子也有红色,那么不就把红色重复记录了吗?所以我们不防把颜色状态用二进制表示,然后用|操作来跟新,举个例子,[1,4]区间的颜色分别是[1,2,2,6],那么它左儿子区间的颜色状态为[1,2]用二进制表示就是011(1和2位有1,代表有颜色1和颜色2),它右儿子区间的颜色状态为[5,6]用二进制表示为00100010,那么区间[1,4]的颜色状态就是011|00100010==00100011,这时候2号颜色就没有被重复记录,是不是很巧妙?,然后我们通过线段树去维护区间颜色状态的二进制就可以了.
AC代码:
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ls dep<<1
#define rs dep<<1|1
using namespace std;
const int Maxn = 1e5+10;
int mask[Maxn*4];
int tag[Maxn*4];
int get_number(int x)
{
int ans = 0;
while(x)
{
ans++;
x&=(x-1);
}
return ans;
}
void pushdown(int dep)
{
if(tag[dep]>=0)
{
mask[ls] = mask[rs] = 1<<tag[dep];
tag[ls] = tag[rs] = tag[dep];
tag[dep] = -1;
return ;
}
}
void pushup(int dep)
{
mask[dep]=(mask[ls]|mask[rs]);
return ;
}
void update(int ql,int qr,int dep,int val,int l,int r)
{
if(ql<=l&&r<=qr)
{
mask[dep] = 1<<val;
tag[dep] = val;
return ;
}
pushdown(dep);
int mid = l+r>>1;
if(ql<=mid) update(ql,qr,ls,val,l,mid);
if(qr>mid) update(ql,qr,rs,val,mid+1,r);
pushup(dep);
return ;
}
int query(int ql,int qr,int dep,int l,int r)
{
if(ql<=l&&r<=qr)
{
return mask[dep];
}
pushdown(dep);
int mid = l+r>>1;
int ret = 0;
if(ql<=mid) ret|=query(ql,qr,ls,l,mid);
if(qr>mid) ret|=query(ql,qr,rs,mid+1,r);
return ret;
}
void build(int pos,int dep,int l,int r)
{
if(l==r)
{
mask[dep] = 1;
return ;
}
int mid = l+r>>1;
if(pos<=mid) build(pos,ls,l,mid);
else build(pos,rs,mid+1,r);
pushup(dep);
return ;
}
int main()
{
for(int i=1;i<Maxn*4;i++) mask[i] = 1;
memset(tag,-1,sizeof(tag));
int n,T,m;
cin>>n>>T>>m;
/*for(int i=1;i<=n;i++)
{
build(i,1,1,n);
}*/
for(int i=1;i<=m;i++)
{
char s[5];
scanf("%s",s);
if(s[0]=='C')
{
int A,B,C;
cin>>A>>B>>C;
update(min(A,B),max(A,B),1,C-1,1,n);
}
else
{
int A,B;
cin>>A>>B;
int ans = get_number(query(min(A,B),max(A,B),1,1,n));
cout<<ans<<'\n';
}
}
return 0;
}
如果还是不太懂这里有篇视频讲的很清楚
视频讲解链接