P10120『STA - R4』冰红茶 题解
分析
出得很好,模板套模板,希望下次再来。
难点在于维护最后连续喝的 DS 饮料数量。设这次喝原味饮料的区间为
与 不相交。如:
在
与 相交。如:
在
这就是操作一转化之后你能维护的东西。说是模板其实是因为这个区间赋值和区间加就是扶苏的问题。这里就不分析了。
然后就是另一个模板——维护操作二。很明显的一个小清新,因为 DS 的数量不增。考虑线段树上的某个区间在什么情况下会有 DS 被干掉。因为 BTC 是干掉连续喝相同饮料数量不少于
对于询问,就是求出来区间
复杂度
小细节:保证小清新的时间复杂度,当一个 DS 被干掉之后,他的最大值应赋值为极小值。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define re register
#define il inline
#define pii pair<int,int>
#define x first
#define y second
#define gc getchar()
#define rd read()
#define debug() puts("------------")
namespace yzqwq{
il int read(){
int x=0,f=1;char ch=gc;
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc;}
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=gc;
return x*f;
}
il int qmi(int a,int b,int p){
int ans=1;
while(b){
if(b&1) ans=ans*a%p;
a=a*a%p,b>>=1;
}
return ans;
}
il auto max(auto a,auto b){return (a>b?a:b);}
il auto min(auto a,auto b){return (a<b?a:b);}
il int gcd(int a,int b){
if(!b) return a;
return gcd(b,a%b);
}
il int lcm(int a,int b){
return a/gcd(a,b)*b;
}
il void exgcd(int a,int b,int &x,int &y){
if(!b) return x=1,y=0,void(0);
exgcd(b,a%b,x,y);
int t=x;
x=y,y=t-a/b*x;
return ;
}
mt19937 rnd(time(0));
}
using namespace yzqwq;
const int N=3e5+10;
int n,q;
pii lst;
struct Tree{
int l,r;
int mx,kil;
int tag1,tag2,tag;
}tr[N<<2];
il void up(int now){
tr[now].mx=max(tr[now<<1].mx,tr[now<<1|1].mx);
tr[now].kil=tr[now<<1].kil+tr[now<<1|1].kil;
return ;
}
il void down(int now){
if(tr[now].tag==1){//覆盖
tr[now<<1].tag1=tr[now<<1|1].tag1=tr[now].tag1;
tr[now<<1].tag2=tr[now<<1|1].tag2=tr[now].tag2;
tr[now<<1].mx=tr[now<<1|1].mx=tr[now].tag1+tr[now].tag2;
tr[now].tag1=tr[now].tag2=tr[now].tag=0;
tr[now<<1].tag=tr[now<<1|1].tag=1;
}
else{//加
tr[now<<1].tag2+=tr[now].tag2,
tr[now<<1|1].tag2+=tr[now].tag2;
tr[now<<1].mx+=tr[now].tag2,
tr[now<<1|1].mx+=tr[now].tag2;
tr[now].tag1=tr[now].tag2=tr[now].tag=0;
}
return ;
}
il void build(int now,int l,int r){
tr[now].l=l,tr[now].r=r;
if(l==r) return ;
int mid=l+r>>1;
build(now<<1,l,mid),build(now<<1|1,mid+1,r);
return ;
}
il void add1(int now,int l,int r,int k){//区间加
if(tr[now].l>=l&&tr[now].r<=r){
tr[now].mx+=k,
tr[now].tag2+=k;
return ;
}
down(now);
int mid=tr[now].l+tr[now].r>>1;
if(l<=mid) add1(now<<1,l,r,k);
if(mid<r) add1(now<<1|1,l,r,k);
return up(now),void(0);
}
il void add2(int now,int l,int r,int k){//区间覆盖
if(tr[now].l>=l&&tr[now].r<=r){
tr[now].mx=tr[now].tag1=k,
tr[now].tag2=0,tr[now].tag=1;
return ;
}
down(now);
int mid=tr[now].l+tr[now].r>>1;
if(l<=mid) add2(now<<1,l,r,k);
if(mid<r) add2(now<<1|1,l,r,k);
return up(now),void(0);
}
il void del(int now,int l,int r,int k){//干掉 DS
if(tr[now].l==tr[now].r){
tr[now].mx=-1e18,tr[now].kil=1;
return ;
}
down(now);
int mid=tr[now].l+tr[now].r>>1;
if(l<=mid&&tr[now<<1].mx>=k&&tr[now<<1].kil<tr[now<<1].r-tr[now<<1].l+1) del(now<<1,l,r,k);
if(mid<r&&tr[now<<1|1].mx>=k&&tr[now<<1|1].kil<tr[now<<1|1].r-tr[now<<1|1].l+1) del(now<<1|1,l,r,k);
return up(now),void(0);
}
il void solve(){
n=rd,q=rd;
build(1,1,n);
for(re int i=1;i<=q;++i){
int op=rd,l,r,k;
if(op==1){
l=rd,r=rd,k=rd;
if(!lst.x) add1(1,1,n,k),lst={l,r};
else{
int l_=lst.x,r_=lst.y;
if(r_<l||r<l_){//区间不相交
if(min(l,l_)>1) add1(1,1,min(l,l_)-1,k);
if(max(r,r_)<n) add1(1,max(r,r_)+1,n,k);
add2(1,l_,r_,k);
add2(1,l,r,k);
if(r_<l&&r_+1<=l-1) add1(1,r_+1,l-1,k);
if(r<l_&&r+1<=l_-1) add1(1,r+1,l_-1,k);
}
else{//区间相交
if(min(l,l_)>1) add1(1,1,min(l,l_)-1,k);
if(max(r,r_)<n) add1(1,max(r,r_)+1,n,k);
add2(1,min(l,l_),max(l,l_)-1,k);
add2(1,min(r,r_)+1,max(r,r_),k);
add1(1,max(l,l_),min(r,r_),k);
}
lst={l,r};
}
}
else if(op==2){
l=rd,r=rd,k=rd;
del(1,l,r,k);
}
else printf("%lld\n",n-tr[1].kil);
}
return ;
}
signed main(){
int t=1;while(t--)
solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!