题解:
当时把题目看错了
线段树维护一个区间里有几段,维护区间左端点和右端点(用来合并)
切分可以就是把有连续的地方都切,有多少地方连续可以通过长度-段数算出来。
#include <iostream>
#include <stdio.h>
#include <algorithm>
const int maxn = 200105;
using namespace std;
#define lt x<<1
#define rt x<<1|1
struct node
{
int num,l,r;
int lazy;
}t[maxn*4];
int a[maxn];
void up(int x)
{
t[x].num=t[lt].num+t[rt].num;
t[x].l=t[lt].l;
t[x].r=t[rt].r;
if(t[lt].r==t[rt].l) t[x].num--;
}
void build(int x,int l,int r)
{
if(l==r){
t[x].l=t[x].r=a[l];
t[x].num=1;
t[x].lazy=0;
return;
}
int mid = (l+r)>>1;
build(lt,l,mid);
build(rt,mid+1,r);
t[x].lazy=0;
up(x);
}
void pushdown(int x)
{
if(t[x].lazy){
int p=t[x].lazy;
t[lt].l=t[lt].r=p;
t[rt].l=t[rt].r=p;
t[lt].num=t[rt].num=1;
t[lt].lazy=t[rt].lazy=p;
t[x].lazy=0;
}
}
void update(int x,int l,int r,int ll,int rr,int p)
{
if(ll<=l&&rr>=r){
t[x].lazy=p;
t[x].l=t[x].r=p;
t[x].num=1;
return;
}
pushdown(x);
int mid = (l+r)>>1;
if(ll<=mid) update(lt, l, mid, ll, rr, p);
if(mid<rr) update(rt, mid+1, r, ll, rr, p);
up(x);
}
int query(int x,int l,int r,int ll,int rr)
{
if(ll<=l&&rr>=r){
return t[x].num;
}
pushdown(x);
int mid = (l+r)>>1;
int ans = 0;
if(ll<=mid){
ans+=query(lt,l,mid,ll,rr);
}
if(mid<rr){
ans+=query(rt,mid+1,r,ll,rr);
}
if(ll<=mid&&mid<rr){
if(t[lt].r==t[rt].l)
ans--;
}
return ans;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
build(1,1,n);
while(m--){
int f,l,r,x;
scanf("%d%d%d%d",&f,&l,&r,&x);
if(f&1){
update(1, 1, n, l, r, x);
}else{
int ans = query(1,1,n,l,r);
printf("%d\n",ans+min(r-l+1-ans,x));
}
}
}