网上的代码有很多但是实现的方式不同,我个人还是比较喜欢带结构体的线段树,
然后本题的关键就在于维护颜色的问题上了,
结构体中的2个变量sum表示是第几种颜色,初始化为1
lazy表示之前是否染过色
如果染过色就把染过的色下传,然后在进行染色
然后就是判断这个点所代表区间的颜色,如果左右区间颜色不同,就令他的颜色为-1,相同就等于左右区间的颜色。
#include<iostream>
#include<algorithm>
#include<fstream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<cmath>
#include<cctype>
#include<vector>
#include<limits.h>
#include<queue>
#include<stack>
using namespace std;
const int maxn=1e5+5;
struct mmp
{
int l,r;
int sum,lazy; //区间左右边界,区间元素之和,懒惰标记
mmp()
{
l=0;
r=0;
sum=0;
lazy=0;
}
};
mmp m[4*maxn]; //线段树的内容从下标1开始存
int p[100];
int ans;
//初始化
void build(int k,int l,int r) //节点编号,左右边界
{
m[k].l=l;
m[k].r=r;
m[k].sum=1;
m[k].lazy=-1;
if(l==r) //递归到叶子结点
{
return ;
}
int mid=(l+r)/2;
build(k*2,l,mid);
build(k*2+1,mid+1,r);
}
void update(int k) //更新节点k的sum
{
if(m[k*2].sum==m[k*2+1].sum)
{
m[k].sum=m[k*2].sum;
}
else
m[k].sum=-1;
//一段区间的元素和等于它的子区间的元素和
}
//下传标记
void pushdown(int k) //将点k的懒惰标记下传
{
if(m[k].l==m[k].r) //如果节点k已经是叶子节点了
{
return ;
}
//给k的子节点重新赋值
m[k*2].sum=m[k].lazy;
m[k*2+1].sum=m[k].lazy;
m[k*2].lazy=m[k].lazy; //下传点k的标记
m[k*2+1].lazy=m[k].lazy;
m[k].lazy=-1;
}
//区间修改
void changeSegment(int k,int l,int r,int x)
//当前节点编号为k,把区间[l,r]内的所有元素+x
{
if(m[k].lazy!=-1) //这个位置要下传标记,不知道为什么,我觉得查询的时候下传标记就可以了
pushdown(k);
if(m[k].l==l&&m[k].r==r) //找到了全部元素都要修改的区间
{
m[k].sum=x; //更新该区间的sum
m[k].lazy=x; //懒惰标记叠加
return ;
}
int mid=(m[k].l+m[k].r)/2;
if(r<=mid) //被修改的区间完全在左区间
changeSegment(2*k,l,r,x);
else if(l>mid)
changeSegment(2*k+1,l,r,x);
else //如果都不在,就要把区间分解成2块,分别在左右区间递归
{
changeSegment(2*k,l,mid,x);
changeSegment(2*k+1,mid+1,r,x);
}
update(k); //记得更新节点k
}
//区间查询
void query(int k,int l,int r) //当前节点为k,查询区间[l,r]
{
if(m[k].sum!=-1||m[k].l==m[k].r)
{
if(p[m[k].sum]==0)
{
p[m[k].sum]=1;
ans++;
}
return ;
}
int mid=(m[k].l+m[k].r)/2;
if(r<=mid) //查询区间被包含在左子区间
query(k*2,l,r);
else if(l>mid)
query(k*2+1,l,r);
else
{
query(2*k,l,mid);
query(2*k+1,mid+1,r);
}
//询问区间跨越2个子区间
}
int main()
{
int n,m,a,b,c,o;
char s[10];
while(scanf("%d%d%d",&n,&o,&m)==3)
{
build(1,1,n);
while(m--)
{
scanf("%s",s);
if(s[0]=='C')
{
scanf("%d%d%d",&a,&b,&c);
if(a>b)
swap(a,b);
changeSegment(1,a,b,c);
}
else
{
scanf("%d%d",&a,&b);
if(a>b)
swap(a,b);
memset(p,0,sizeof(p));
ans=0;
query(1,a,b);
printf("%d\n",ans);
}
}
}
return 0;
}