题目大意:给出
n
n
n面墙的初始颜色,
m
m
m个询问
(
a
,
l
,
r
,
z
)
(a,l,r,z)
(a,l,r,z),如果
a
=
1
a=1
a=1,表示把
[
l
,
r
]
[l,r]
[l,r]的所有墙染成
z
z
z,如果
a
=
2
a=2
a=2,表示查询
[
l
,
r
]
[l,r]
[l,r]的颜色为
z
z
z的墙的数量。
思路:线段树比分块哈希快得多……就离谱。修改操作就不多说了,一个 l a z y lazy lazy标记就行了,主要是查询,暴力找肯定不行,我们维护一个区间最大值和区间最小值,判断要查询的颜色是否在这个范围内,这样就可以省去很多时间。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
struct Tree
{
int l,r,lazy,MAX,MIN;
}tree[maxn<<2];
int n,m;
inline void up(int i)
{
int l=i<<1,r=i<<1|1;
tree[i].MAX=max(tree[l].MAX,tree[r].MAX);
tree[i].MIN=min(tree[l].MIN,tree[r].MIN);
}
inline void down(int i)
{
int l=i<<1,r=i<<1|1;
tree[l].lazy=tree[r].lazy=tree[i].lazy;
tree[l].MAX=tree[l].MIN=tree[i].lazy;
tree[r].MAX=tree[r].MIN=tree[i].lazy;
tree[i].lazy=-1;
}
void build(int i,int l,int r)
{
tree[i].lazy=-1;
tree[i].l=l,tree[i].r=r;
if(l==r)
{
scanf("%d",&tree[i].MAX);
tree[i].MIN=tree[i].MAX;
return ;
}
int mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
up(i);
}
void update(int i,int l,int r,int v)
{
if(tree[i].l==l&&tree[i].r==r)
{
tree[i].lazy=v;
tree[i].MAX=tree[i].MIN=v;
return ;
}
if(tree[i].lazy!=-1)
down(i);
int mid=(tree[i].l+tree[i].r)>>1;
if(r<=mid)
update(i<<1,l,r,v);
else if(l>mid)
update(i<<1|1,l,r,v);
else
update(i<<1,l,mid,v),update(i<<1|1,mid+1,r,v);
up(i);
}
int query(int i,int l,int r,int v)
{
if(tree[i].MAX<v||tree[i].MIN>v)
return 0;
if(tree[i].l==l&&tree[i].r==r)
{
if(tree[i].lazy!=-1)
{
if(tree[i].lazy==v)
return r-l+1;
return 0;
}
if(l==r)
{
if(tree[i].MAX==v)
return 1;
return 0;
}
}
if(tree[i].lazy!=-1)
down(i);
int mid=(tree[i].l+tree[i].r)>>1;
if(r<=mid)
return query(i<<1,l,r,v);
else if(l>mid)
return query(i<<1|1,l,r,v);
else
return query(i<<1,l,mid,v)+query(i<<1|1,mid+1,r,v);
up(i);
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
build(1,1,n);
int op,l,r,v;
while(m--)
{
scanf("%d%d%d%d",&op,&l,&r,&v);
++l,++r;
if(op==1)
update(1,l,r,v);
else
printf("%d\n",query(1,l,r,v));
}
}
return 0;
}