洛谷——P2801 教主的魔法(线段树or分块)
P2801 教主的魔法
(1) 若第一个字母为“M”,则紧接着有三个数字L、R、W。表示对闭区间 [L, R] 内所有英雄的身高加上W。
(2) 若第一个字母为“A”,则紧接着有三个数字L、R、C。询问闭区间 [L, R] 内有多少英雄的身高大于等于C。
线段树大法好
维护区间$max$和区间$min$
修改,正常修改即可,push_up操作修改的也只是区间最大值和最小值
关键在于查找,若当前区间的最大值$<=$所要查询的值,返回0
若当前区间的最小值$>=$所要查询的值,返回$r-l+1$
想不到啊,维护区间最大值和最小值还能进行这样的骚操作啊,还是太蒟了。。。qwq
这题分块可做,可蒟蒻(博主)不会啊。。。
#include<bits/stdc++.h> #define N 10000000 using namespace std; struct Segment{ int l,r,mw,mi,f; }tr[N]; void push_up(int k){ tr[k].mi=min(tr[k<<1].mi,tr[k<<1|1].mi); tr[k].mw=max(tr[k<<1].mw,tr[k<<1|1].mw); } void build(int k,int l,int r){ tr[k].l=l,tr[k].r=r; if(l==r) {scanf("%d",&tr[k].mi),tr[k].mw=tr[k].mi;return;} int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); push_up(k); } void push_down(int k){ if(tr[k].f){ int f=tr[k].f; tr[k<<1].mi+=f,tr[k<<1].mw+=f; tr[k<<1].f+=f, tr[k<<1|1].mi+=f,tr[k<<1|1].mw+=f; tr[k<<1|1].f+=f, tr[k].f=0; } } void update(int k,int ql,int qr,int f){ int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1; if(l>=ql&&r<=qr) {tr[k].mi+=f,tr[k].mw+=f;tr[k].f+=f;return;} push_down(k); if(ql<=mid) update(k<<1,ql,qr,f); if(qr>mid) update(k<<1|1,ql,qr,f); push_up(k); } int query(int k,int ql,int qr,int val){ int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1; if(l>=ql&&r<=qr&&tr[k].mi>=val) return r-l+1; if(l>=ql&&r<=qr&&tr[k].mw<val) return 0; push_down(k); int ans=0; if(ql<=mid) ans+=query(k<<1,ql,qr,val); if(qr>mid) ans+=query(k<<1|1,ql,qr,val); push_up(k); return ans; } int n,q; int main() { scanf("%d%d",&n,&q); build(1,1,n); for(int l,r,x,i=1;i<=q;i++){ char p; cin>>p; scanf("%d%d%d",&l,&r,&x); if(p=='M') update(1,l,r,x); else{ printf("%d\n",query(1,l,r,x)); } } return 0; }
博主蒟蒻,若有出错的地方,敬请指出。
如有侵犯您版权的地方,请快速联系我,我会撤回本博文。