题目链接:点击打开链接
题目大意:
有n个数,m次操作
1.将区间内所有的数变为x
2.查询l r区间切割k的之后的value值(把一段区间切割k次之后,这个k+1个区间的value值之和最大是多少)
一个区间的value值就是这个区间内每个子间隔中不同连续数字的总和,总体来说就是 1 1 2 2 1 1 就算3
解题思路:
其实我们可以发现,区间切割在正常情况下每次切割都是将最后的答案+1,例如一个区间内所有数相等的情况。但是有一种情况切割对答案是没有影响的。
例如 1 1 1 2 2 2 ,这时我们会发现我们如果切割在1 2 之间 的这个位置 ,这次切割就对最终答案是没有影响的。所以我们要尽量选择切割两边数有相同的切割点,那么我们就需要统计这个区间有多少段连续的相同的数 例如 1 1 2 2 3 3 的值就是3 这样的。
之后统计哪些切割位置对答案有贡献最后记录结果就好了,维护过程就是线段树的区间维护,记录每个区间的最左值和最右值,合并的时候如果lson的最右值和rson的最左值相同的话,当前的sum就是lson.sum+rson.sum-1,否则就正常相加,
Ac代码:
#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
const int INF=1e9+7;
const int mod=998244353;
int n,m,a[maxn];
struct node
{
int l,r,sum,lazy;
int lx,rx;
}t[maxn<<2];
void pushup(int rt) //pushup
{
t[rt].sum=t[lson].sum+t[rson].sum;
if(t[lson].rx==t[rson].lx) t[rt].sum--; //判断是否需要减1
t[rt].lx=t[lson].lx,t[rt].rx=t[rson].rx;
}
void pushdown(int rt)
{
if(t[rt].lazy)
{
t[lson].lx=t[lson].rx=t[rt].lx; //正常的pushdown操作
t[rson].lx=t[rson].rx=t[rt].rx;
t[lson].lazy=t[rson].lazy=1;
t[lson].sum=t[rson].sum=1;
t[rt].lazy=0;
}
}
void build(int l,int r,int rt)
{
int mid=(l+r)>>1;
t[rt].l=l,t[rt].r=r;
if(l==r)
{
t[rt].lx=t[rt].rx=a[l];
t[rt].sum=1;
return ;
}
build(l,mid,lson);
build(mid+1,r,rson);
pushup(rt);
}
void update(int l,int r,int x,int rt) //正常的区间更新
{
int mid=(t[rt].l+t[rt].r)>>1;
if(l<=t[rt].l&&t[rt].r<=r)
{
t[rt].lx=x,t[rt].rx=x;
t[rt].lazy=1,t[rt].sum=1;
return ;
}
pushdown(rt);
if(l<=mid) update(l,r,x,lson);
if(r>mid) update(l,r,x,rson);
pushup(rt);
}
int query(int l,int r,int rt) //查询
{
int mid=(t[rt].l+t[rt].r)>>1,ans=0;
if(l<=t[rt].l&&t[rt].r<=r)
return t[rt].sum;
pushdown(rt);
if(l<=mid)
{
ans+=query(l,r,lson);
if(r>mid&&t[rson].lx==t[lson].rx) ans--; //注意这个地方--
}
if(r>mid)
ans+=query(l,r,rson);
pushup(rt);
return ans;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,n,1);
while(m--)
{
int flag,l,r,x;
scanf("%d%d%d%d",&flag,&l,&r,&x);
if(flag==1) update(l,r,x,1);
if(flag==2)
{
int ans=query(l,r,1);
printf("%d\n",ans+min(r-l-ans+1,x)); //这个地方就是统计出有哪些间隔是有价值的 取它和k的较小值加上即可
}
}
}
}