这题真的挺简单的……模拟的时候我十五分钟就切掉了……
维护区间最值,查询的时候 w > 最大返回0,w <= 最小返回区间长度,否则找两个子区间。
我把模拟代码交到洛谷上50分……发现自己在找子区间的时候忘了pushdown……(模拟数据真的好水啊……听说直接暴力改都满分……)
但是常数可能有点大,这个要看题是否故意卡掉线段树了。个人认为,这道题想卡什么都很容易……
whisper:数据下次不要这么水可以嘛…
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<queue> #include<cmath> #include<algorithm> using namespace std; #define maxn 4000005 #define ls now<<1 #define rs now<<1|1 int lazy[maxn],M[maxn],S[maxn],l[maxn],r[maxn]; int n,m; void up(int now) { M[now]=max(M[ls],M[rs]); S[now]=min(S[ls],S[rs]); } void build(int now,int L,int R) { l[now]=L; r[now]=R; if(L==R) { scanf("%d",&M[now]); S[now]=M[now]; return ; } int mid=(L+R)>>1; build(ls,L,mid); build(rs,mid+1,R); up(now); } void pushdown(int now) { if(!lazy[now]) return ; lazy[ls]+=lazy[now]; lazy[rs]+=lazy[now]; M[ls]+=lazy[now]; S[ls]+=lazy[now]; M[rs]+=lazy[now]; S[rs]+=lazy[now]; lazy[now]=0; } void update(int now,int L,int R,int w) { if(l[now]==L&&r[now]==R) { M[now]+=w; S[now]+=w; lazy[now]+=w; return ; } pushdown(now); int mid=(l[now]+r[now])>>1; if(R<=mid) update(ls,L,R,w); else if(L>mid) update(rs,L,R,w); else { update(ls,L,mid,w); update(rs,mid+1,R,w); } up(now); } int query(int now,int L,int R,int w) { if(l[now]==L&&r[now]==R) { if(l[now]!=r[now]) pushdown(now); if(M[now]<w) return 0; else if(S[now]>=w) return r[now]-l[now]+1; else return query(ls,l[ls],r[ls],w)+query(rs,l[rs],r[rs],w); } pushdown(now); int mid=(l[now]+r[now])>>1; if(R<=mid) return query(ls,L,R,w); else if(L>mid) return query(rs,L,R,w); else return query(ls,L,mid,w)+query(rs,mid+1,R,w); } int main() { //freopen("magic.in","r",stdin); //freopen("magic.out","w",stdout); scanf("%d%d",&n,&m); build(1,1,n); for(int i=1;i<=m;i++) { char s; int L,R,w; cin>>s; scanf("%d%d%d",&L,&R,&w); if(s=='M') update(1,L,R,w); else printf("%d\n",query(1,L,R,w)); } return 0; }